From ed3bf0e62b5f8b3046b8717dcef54c6b98cb7e77 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 15 Apr 2017 15:53:02 -0400 Subject: [PATCH] Fix mixed line endings. --- .../Classes/ExternalToolManager.cs | 394 ++-- .../tools/Watch/WatchList/WatchList.cs | 1260 ++++++------ .../AVOut/Quantize/OctreeQuantizer.cs | 1112 +++++----- .../AVOut/Quantize/PaletteTable.cs | 146 +- .../AVOut/Quantize/Quantizer.cs | 698 +++---- .../CustomControls/ExceptionBox.cs | 170 +- .../CustomControls/InputRoll.Drawing.cs | 1230 +++++------ BizHawk.Client.EmuHawk/FileLoader.cs | 698 +++---- BizHawk.Client.EmuHawk/GLManager.cs | 196 +- .../config/PSX/PSXControllerConfigNew.cs | 184 +- BizHawk.Client.EmuHawk/tools/CDL.cs | 886 ++++---- .../tools/HexEditor/NewHexEditor.cs | 206 +- .../CallbackBasedTraceBuffer.cs | 122 +- .../Serial/Drive1541.FluxTransitions.cs | 260 +-- .../Computers/Commodore64/User/UserPort.cs | 84 +- .../Intellivision.IMemoryDomains.cs | 236 +-- .../NES/Boards/MMC3_family/Mapper121.cs | 168 +- .../NES/Boards/MMC3_family/Mapper219.cs | 62 +- .../NES/Boards/MMC3_family/Mapper223.cs | 56 +- .../Consoles/Nintendo/NES/Boards/Mapper125.cs | 122 +- .../Consoles/Nintendo/NES/Boards/Mapper142.cs | 230 +-- .../Nintendo/QuickNES/Nes_NTSC_Colors.cs | 12 +- .../Consoles/Sega/gpgx/GPGX.ISettable.cs | 538 ++--- .../Consoles/Sega/gpgx/GPGX.IVideoProvider.cs | 114 +- .../Consoles/Sony/PSX/Octoshock.ITraceable.cs | 78 +- BizHawk.Emulation.Cores/Libretro/LibRetro.cs | 1328 ++++++------ .../Libretro/LibRetroEmulator.cs | 1820 ++++++++--------- Bizware/BizHawk.Bizware.BizwareGL/CGC.cs | 216 +- .../BizHawk.Bizware.BizwareGL/RetroShader.cs | 174 +- 29 files changed, 6400 insertions(+), 6400 deletions(-) diff --git a/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs b/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs index 3dfa1e3d26..7dada85b17 100644 --- a/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs +++ b/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs @@ -1,198 +1,198 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Reflection; - -using System.Windows.Forms; -using BizHawk.Client.Common; - -namespace BizHawk.Client.ApiHawk -{ - /// - /// This static class handle all ExternalTools - /// - public static class ExternalToolManager - { - #region Fields - - private static FileSystemWatcher directoryMonitor; - private static List menuItems = new List(); - - #endregion - - #region cTor(s) - - /// - /// Initilization - /// - static ExternalToolManager() - { - if(!Directory.Exists(Global.Config.PathEntries["Global", "External Tools"].Path)) - { - Directory.CreateDirectory(Global.Config.PathEntries["Global", "External Tools"].Path); - } - directoryMonitor = new FileSystemWatcher(Global.Config.PathEntries["Global", "External Tools"].Path, "*.dll"); - directoryMonitor.IncludeSubdirectories = false; - directoryMonitor.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName; - directoryMonitor.Filter = "*.dll"; - directoryMonitor.Created += new FileSystemEventHandler(DirectoryMonitor_Created); - directoryMonitor.EnableRaisingEvents = true; - - ClientApi.RomLoaded += delegate { BuildToolStrip(); }; - - BuildToolStrip(); - } - - #endregion - - #region Methods - - /// - /// Build the toolstrip menu - /// - private static void BuildToolStrip() - { - menuItems.Clear(); - if (Directory.Exists(directoryMonitor.Path)) - { - DirectoryInfo dInfo = new DirectoryInfo(directoryMonitor.Path); - - foreach (FileInfo fi in dInfo.GetFiles("*.dll")) - { - menuItems.Add(GenerateToolTipFromFileName(fi.FullName)); - } - } - } - - /// - /// Generate a from an - /// external tool dll. - /// The assembly must have in its - /// assembly attributes - /// - /// File that will be reflected - /// A new ; assembly path can be found in the Tag property - /// For the moment, you could only load a dll that have a form (which implements ) - private static ToolStripMenuItem GenerateToolTipFromFileName(string fileName) - { - Type customFormType; - Assembly externalToolFile; - ToolStripMenuItem item = null; - - try +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; + +using System.Windows.Forms; +using BizHawk.Client.Common; + +namespace BizHawk.Client.ApiHawk +{ + /// + /// This static class handle all ExternalTools + /// + public static class ExternalToolManager + { + #region Fields + + private static FileSystemWatcher directoryMonitor; + private static List menuItems = new List(); + + #endregion + + #region cTor(s) + + /// + /// Initilization + /// + static ExternalToolManager() + { + if(!Directory.Exists(Global.Config.PathEntries["Global", "External Tools"].Path)) { - BizHawk.Common.Win32Hacks.RemoveMOTW(fileName); - externalToolFile = Assembly.LoadFrom(fileName); - object[] attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolAttribute), false); - if (attributes != null && attributes.Count() == 1) - { - BizHawkExternalToolAttribute attribute = (BizHawkExternalToolAttribute)attributes[0]; - item = new ToolStripMenuItem(attribute.Name); - item.ToolTipText = attribute.Description; - if (attribute.IconResourceName != string.Empty) - { - Stream s = externalToolFile.GetManifestResourceStream(string.Format("{0}.{1}", externalToolFile.GetName().Name, attribute.IconResourceName)); - if (s != null) - { - item.Image = new Bitmap(s); - } - } - - customFormType = externalToolFile.GetTypes().FirstOrDefault(t => t != null && t.FullName == "BizHawk.Client.EmuHawk.CustomMainForm"); - if (customFormType == null) - { - item.ToolTipText = "Does not have a CustomMainForm"; - item.Enabled = false; - } - item.Tag = fileName; - - attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolUsageAttribute), false); - if (attributes != null && attributes.Count() == 1) - { - BizHawkExternalToolUsageAttribute attribute2 = (BizHawkExternalToolUsageAttribute)attributes[0]; - if(Global.Emulator.SystemId == "NULL" && attribute2.ToolUsage != BizHawkExternalToolUsage.Global) - { - item.ToolTipText = "This tool doesn't work if nothing is loaded"; - item.Enabled = false; - } - else if(attribute2.ToolUsage == BizHawkExternalToolUsage.EmulatorSpecific && Global.Emulator.SystemId != ClientApi.SystemIdConverter.ConvertBack(attribute2.System)) - { - item.ToolTipText = "This tool doesn't work for current system"; - item.Enabled = false; - } - else if (attribute2.ToolUsage == BizHawkExternalToolUsage.GameSpecific && Global.Game.Hash != attribute2.GameHash) - { - item.ToolTipText = "This tool doesn't work for current game"; - item.Enabled = false; - } - } - } - else - { - item = new ToolStripMenuItem(externalToolFile.GetName().Name); - item.ToolTipText = "BizHawkExternalTool attribute hasn't been found"; - item.Enabled = false; - } - } - catch (BadImageFormatException) - { - item = new ToolStripMenuItem(fileName); - item.ToolTipText = "This is not an assembly"; - item.Enabled = false; - } - -#if DEBUG //I added special debug stuff to get additionnal informations. Don(t think it can be usefull for released versions - catch (ReflectionTypeLoadException ex) - { - foreach (Exception e in ex.LoaderExceptions) - { - Debug.WriteLine(e.Message); - } - item.ToolTipText = "Something goes wrong while trying to load"; - item.Enabled = false; - } -#else - catch (ReflectionTypeLoadException) - { - item.ToolTipText = "Something goes wrong while trying to load"; - item.Enabled = false; - } -#endif - - return item; - } - - /// - /// This event is raised when we add a dll file into - /// the external tools path. - /// It will automatically load the assembly and add it into the list - /// - /// Object that raised the event - /// Event arguments - private static void DirectoryMonitor_Created(object sender, FileSystemEventArgs e) - { - menuItems.Add(GenerateToolTipFromFileName(e.FullPath)); - } - - #endregion - - #region Properties - - /// - /// Gets a prebuild - /// This list auto-updated by the itself - /// - public static IEnumerable ToolStripMenu - { - get - { - return menuItems; - } - } - - #endregion - } -} + Directory.CreateDirectory(Global.Config.PathEntries["Global", "External Tools"].Path); + } + directoryMonitor = new FileSystemWatcher(Global.Config.PathEntries["Global", "External Tools"].Path, "*.dll"); + directoryMonitor.IncludeSubdirectories = false; + directoryMonitor.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName; + directoryMonitor.Filter = "*.dll"; + directoryMonitor.Created += new FileSystemEventHandler(DirectoryMonitor_Created); + directoryMonitor.EnableRaisingEvents = true; + + ClientApi.RomLoaded += delegate { BuildToolStrip(); }; + + BuildToolStrip(); + } + + #endregion + + #region Methods + + /// + /// Build the toolstrip menu + /// + private static void BuildToolStrip() + { + menuItems.Clear(); + if (Directory.Exists(directoryMonitor.Path)) + { + DirectoryInfo dInfo = new DirectoryInfo(directoryMonitor.Path); + + foreach (FileInfo fi in dInfo.GetFiles("*.dll")) + { + menuItems.Add(GenerateToolTipFromFileName(fi.FullName)); + } + } + } + + /// + /// Generate a from an + /// external tool dll. + /// The assembly must have in its + /// assembly attributes + /// + /// File that will be reflected + /// A new ; assembly path can be found in the Tag property + /// For the moment, you could only load a dll that have a form (which implements ) + private static ToolStripMenuItem GenerateToolTipFromFileName(string fileName) + { + Type customFormType; + Assembly externalToolFile; + ToolStripMenuItem item = null; + + try + { + BizHawk.Common.Win32Hacks.RemoveMOTW(fileName); + externalToolFile = Assembly.LoadFrom(fileName); + object[] attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolAttribute), false); + if (attributes != null && attributes.Count() == 1) + { + BizHawkExternalToolAttribute attribute = (BizHawkExternalToolAttribute)attributes[0]; + item = new ToolStripMenuItem(attribute.Name); + item.ToolTipText = attribute.Description; + if (attribute.IconResourceName != string.Empty) + { + Stream s = externalToolFile.GetManifestResourceStream(string.Format("{0}.{1}", externalToolFile.GetName().Name, attribute.IconResourceName)); + if (s != null) + { + item.Image = new Bitmap(s); + } + } + + customFormType = externalToolFile.GetTypes().FirstOrDefault(t => t != null && t.FullName == "BizHawk.Client.EmuHawk.CustomMainForm"); + if (customFormType == null) + { + item.ToolTipText = "Does not have a CustomMainForm"; + item.Enabled = false; + } + item.Tag = fileName; + + attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolUsageAttribute), false); + if (attributes != null && attributes.Count() == 1) + { + BizHawkExternalToolUsageAttribute attribute2 = (BizHawkExternalToolUsageAttribute)attributes[0]; + if(Global.Emulator.SystemId == "NULL" && attribute2.ToolUsage != BizHawkExternalToolUsage.Global) + { + item.ToolTipText = "This tool doesn't work if nothing is loaded"; + item.Enabled = false; + } + else if(attribute2.ToolUsage == BizHawkExternalToolUsage.EmulatorSpecific && Global.Emulator.SystemId != ClientApi.SystemIdConverter.ConvertBack(attribute2.System)) + { + item.ToolTipText = "This tool doesn't work for current system"; + item.Enabled = false; + } + else if (attribute2.ToolUsage == BizHawkExternalToolUsage.GameSpecific && Global.Game.Hash != attribute2.GameHash) + { + item.ToolTipText = "This tool doesn't work for current game"; + item.Enabled = false; + } + } + } + else + { + item = new ToolStripMenuItem(externalToolFile.GetName().Name); + item.ToolTipText = "BizHawkExternalTool attribute hasn't been found"; + item.Enabled = false; + } + } + catch (BadImageFormatException) + { + item = new ToolStripMenuItem(fileName); + item.ToolTipText = "This is not an assembly"; + item.Enabled = false; + } + +#if DEBUG //I added special debug stuff to get additionnal informations. Don(t think it can be usefull for released versions + catch (ReflectionTypeLoadException ex) + { + foreach (Exception e in ex.LoaderExceptions) + { + Debug.WriteLine(e.Message); + } + item.ToolTipText = "Something goes wrong while trying to load"; + item.Enabled = false; + } +#else + catch (ReflectionTypeLoadException) + { + item.ToolTipText = "Something goes wrong while trying to load"; + item.Enabled = false; + } +#endif + + return item; + } + + /// + /// This event is raised when we add a dll file into + /// the external tools path. + /// It will automatically load the assembly and add it into the list + /// + /// Object that raised the event + /// Event arguments + private static void DirectoryMonitor_Created(object sender, FileSystemEventArgs e) + { + menuItems.Add(GenerateToolTipFromFileName(e.FullPath)); + } + + #endregion + + #region Properties + + /// + /// Gets a prebuild + /// This list auto-updated by the itself + /// + public static IEnumerable ToolStripMenu + { + get + { + return menuItems; + } + } + + #endregion + } +} diff --git a/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs b/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs index b9a134798b..e074022cea 100644 --- a/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs +++ b/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs @@ -1,632 +1,632 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using BizHawk.Common.NumberExtensions; -using BizHawk.Common.StringExtensions; -using BizHawk.Emulation.Common; - - -namespace BizHawk.Client.Common -{ - /// - /// This class hold a collection - /// Different memory domain can be mixed - /// - public sealed partial class WatchList - : IList - { - #region Fields - - public const string ADDRESS = "AddressColumn"; - public const string VALUE = "ValueColumn"; - public const string PREV = "PrevColumn"; - public const string CHANGES = "ChangesColumn"; - public const string DIFF = "DiffColumn"; - public const string DOMAIN = "DomainColumn"; - public const string NOTES = "NotesColumn"; - - private static readonly WatchDomainComparer domainComparer = new WatchDomainComparer(); - private static readonly WatchAddressComparer addressComparer = new WatchAddressComparer(); - private static readonly WatchValueComparer valueComparer = new WatchValueComparer(); - private static readonly WatchPreviousValueComparer previousValueComparer = new WatchPreviousValueComparer(); - private static readonly WatchValueDifferenceComparer valueDifferenceComparer = new WatchValueDifferenceComparer(); - private static readonly WatchChangeCountComparer changeCountComparer = new WatchChangeCountComparer(); - private static readonly WatchNoteComparer noteComparer = new WatchNoteComparer(); - - private IMemoryDomains _memoryDomains; - - private List _watchList = new List(0); - private string _currentFilename = string.Empty; - private string _systemid; - - #endregion - - #region cTor(s) - - /// - /// Initialize a new instance of that will - /// contains a set of - /// - /// All available memomry domains - /// Domain you want to watch - /// System identifier (NES, SNES, ...) - public WatchList(IMemoryDomains core, string systemid) - { - _memoryDomains = core; - _systemid = systemid; - } - - #endregion - - #region Methods - - #region ICollection - - /// - /// Adds a into the current collection - /// - /// to add - public void Add(Watch watch) - { - _watchList.Add(watch); - Changes = true; - } - - /// - /// Removes all item from the current collection - /// Clear also the file name - /// - public void Clear() - { - _watchList.Clear(); - Changes = false; - _currentFilename = string.Empty; - } - - /// - /// Determines if the current contains the - /// specified - /// - /// The object to - /// - public bool Contains(Watch watch) - { - return _watchList.Contains(watch); - } - - /// - /// Copies the elements of the current - /// into an starting at a particular index - /// - /// The one-dimension that will serve as destination to copy - /// Zero-based index where the copy should starts - /// - /// - /// - public void CopyTo(Watch[] array, int arrayIndex) - { - _watchList.CopyTo(array, arrayIndex); - } - - /// - /// Removes the first of specified - /// - /// to remove - /// True if successfully removed; otherwise, false - public bool Remove(Watch watch) - { - bool result = _watchList.Remove(watch); - if (result) - { - Changes = true; - } - - return result; - } - - #endregion - - #region IList - - /// - /// Determines the zero-base position of the specified - /// into the - /// - /// to look for - /// Zero-base position if has been found; otherwise -1 - public int IndexOf(Watch watch) - { - return _watchList.IndexOf(watch); - } - - /// - /// Insert a at the specified index - /// - /// The zero-base index where the should be inserted - /// to insert - /// - public void Insert(int index, Watch watch) - { - _watchList.Insert(index, watch); - } - - /// - /// Removes item at the specified index - /// - /// Zero-based index of the to remove - /// - public void RemoveAt(int index) - { - _watchList.RemoveAt(index); - Changes = true; - } - - #endregion IList - - #region IEnumerable - - /// - /// Returns an enumerator that iterates through the collection - /// - /// An for the current collection - public IEnumerator GetEnumerator() - { - return _watchList.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through the collection - /// - /// An for the current collection - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion IEnumerable - - /// - /// Add an existing collection of into the current one - /// equality will be checked to avoid doubles - /// - /// of watch to merge - public void AddRange(IEnumerable watches) - { - Parallel.ForEach(watches, watch => - { - if (!_watchList.Contains(watch)) - { - _watchList.Add(watch); - } - }); - Changes = true; - } - - /// - /// Clears change count of all in the collection - /// - public void ClearChangeCounts() - { - Parallel.ForEach(_watchList, watch => watch.ClearChangeCount()); - } - - /// - /// Sort the current list based on one of the constant - /// - /// Value that specify sorting base - /// Value that define the ordering. Ascending (true) or desceding (false) - public void OrderWatches(string column, bool reverse) - { - switch (column) - { - case ADDRESS: - if (reverse) - { - _watchList.Sort(addressComparer); - _watchList.Reverse(); - } - else - { - _watchList.Sort(); - } - - break; - - case VALUE: - if (reverse) - { - _watchList.Sort(valueComparer); - _watchList.Reverse(); - } - else - { - _watchList.Sort(valueComparer); - } - - break; - - case PREV: - if (reverse) - { - _watchList.Sort(previousValueComparer); - _watchList.Reverse(); - } - else - { - _watchList.Sort(previousValueComparer); - } - - break; - - case DIFF: - if (reverse) - { - _watchList.Sort(valueDifferenceComparer); - _watchList.Reverse(); - } - else - { - _watchList.Sort(valueDifferenceComparer); - } - break; - - case CHANGES: - if (reverse) - { - _watchList.Sort(changeCountComparer); - _watchList.Reverse(); - } - else - { - _watchList.Sort(changeCountComparer); - } - - break; - - case DOMAIN: - if (reverse) - { - _watchList.Sort(domainComparer); - _watchList.Reverse(); - } - else - { - _watchList.Sort(domainComparer); - } - - break; - - case NOTES: - if (reverse) - { - _watchList.Sort(noteComparer); - _watchList.Reverse(); - } - else - { - _watchList.Sort(noteComparer); - } - - break; - } - } - - /// - /// Sets WatchList's domain list to a new one - /// domain will also be refreshed - /// - /// New domains - public void RefreshDomains(IMemoryDomains core) - { - _memoryDomains = core; - Parallel.ForEach(_watchList, watch => +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using BizHawk.Common.NumberExtensions; +using BizHawk.Common.StringExtensions; +using BizHawk.Emulation.Common; + + +namespace BizHawk.Client.Common +{ + /// + /// This class hold a collection + /// Different memory domain can be mixed + /// + public sealed partial class WatchList + : IList + { + #region Fields + + public const string ADDRESS = "AddressColumn"; + public const string VALUE = "ValueColumn"; + public const string PREV = "PrevColumn"; + public const string CHANGES = "ChangesColumn"; + public const string DIFF = "DiffColumn"; + public const string DOMAIN = "DomainColumn"; + public const string NOTES = "NotesColumn"; + + private static readonly WatchDomainComparer domainComparer = new WatchDomainComparer(); + private static readonly WatchAddressComparer addressComparer = new WatchAddressComparer(); + private static readonly WatchValueComparer valueComparer = new WatchValueComparer(); + private static readonly WatchPreviousValueComparer previousValueComparer = new WatchPreviousValueComparer(); + private static readonly WatchValueDifferenceComparer valueDifferenceComparer = new WatchValueDifferenceComparer(); + private static readonly WatchChangeCountComparer changeCountComparer = new WatchChangeCountComparer(); + private static readonly WatchNoteComparer noteComparer = new WatchNoteComparer(); + + private IMemoryDomains _memoryDomains; + + private List _watchList = new List(0); + private string _currentFilename = string.Empty; + private string _systemid; + + #endregion + + #region cTor(s) + + /// + /// Initialize a new instance of that will + /// contains a set of + /// + /// All available memomry domains + /// Domain you want to watch + /// System identifier (NES, SNES, ...) + public WatchList(IMemoryDomains core, string systemid) + { + _memoryDomains = core; + _systemid = systemid; + } + + #endregion + + #region Methods + + #region ICollection + + /// + /// Adds a into the current collection + /// + /// to add + public void Add(Watch watch) + { + _watchList.Add(watch); + Changes = true; + } + + /// + /// Removes all item from the current collection + /// Clear also the file name + /// + public void Clear() + { + _watchList.Clear(); + Changes = false; + _currentFilename = string.Empty; + } + + /// + /// Determines if the current contains the + /// specified + /// + /// The object to + /// + public bool Contains(Watch watch) + { + return _watchList.Contains(watch); + } + + /// + /// Copies the elements of the current + /// into an starting at a particular index + /// + /// The one-dimension that will serve as destination to copy + /// Zero-based index where the copy should starts + /// + /// + /// + public void CopyTo(Watch[] array, int arrayIndex) + { + _watchList.CopyTo(array, arrayIndex); + } + + /// + /// Removes the first of specified + /// + /// to remove + /// True if successfully removed; otherwise, false + public bool Remove(Watch watch) + { + bool result = _watchList.Remove(watch); + if (result) + { + Changes = true; + } + + return result; + } + + #endregion + + #region IList + + /// + /// Determines the zero-base position of the specified + /// into the + /// + /// to look for + /// Zero-base position if has been found; otherwise -1 + public int IndexOf(Watch watch) + { + return _watchList.IndexOf(watch); + } + + /// + /// Insert a at the specified index + /// + /// The zero-base index where the should be inserted + /// to insert + /// + public void Insert(int index, Watch watch) + { + _watchList.Insert(index, watch); + } + + /// + /// Removes item at the specified index + /// + /// Zero-based index of the to remove + /// + public void RemoveAt(int index) + { + _watchList.RemoveAt(index); + Changes = true; + } + + #endregion IList + + #region IEnumerable + + /// + /// Returns an enumerator that iterates through the collection + /// + /// An for the current collection + public IEnumerator GetEnumerator() + { + return _watchList.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through the collection + /// + /// An for the current collection + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion IEnumerable + + /// + /// Add an existing collection of into the current one + /// equality will be checked to avoid doubles + /// + /// of watch to merge + public void AddRange(IEnumerable watches) + { + Parallel.ForEach(watches, watch => + { + if (!_watchList.Contains(watch)) + { + _watchList.Add(watch); + } + }); + Changes = true; + } + + /// + /// Clears change count of all in the collection + /// + public void ClearChangeCounts() + { + Parallel.ForEach(_watchList, watch => watch.ClearChangeCount()); + } + + /// + /// Sort the current list based on one of the constant + /// + /// Value that specify sorting base + /// Value that define the ordering. Ascending (true) or desceding (false) + public void OrderWatches(string column, bool reverse) + { + switch (column) + { + case ADDRESS: + if (reverse) + { + _watchList.Sort(addressComparer); + _watchList.Reverse(); + } + else + { + _watchList.Sort(); + } + + break; + + case VALUE: + if (reverse) + { + _watchList.Sort(valueComparer); + _watchList.Reverse(); + } + else + { + _watchList.Sort(valueComparer); + } + + break; + + case PREV: + if (reverse) + { + _watchList.Sort(previousValueComparer); + _watchList.Reverse(); + } + else + { + _watchList.Sort(previousValueComparer); + } + + break; + + case DIFF: + if (reverse) + { + _watchList.Sort(valueDifferenceComparer); + _watchList.Reverse(); + } + else + { + _watchList.Sort(valueDifferenceComparer); + } + break; + + case CHANGES: + if (reverse) + { + _watchList.Sort(changeCountComparer); + _watchList.Reverse(); + } + else + { + _watchList.Sort(changeCountComparer); + } + + break; + + case DOMAIN: + if (reverse) + { + _watchList.Sort(domainComparer); + _watchList.Reverse(); + } + else + { + _watchList.Sort(domainComparer); + } + + break; + + case NOTES: + if (reverse) + { + _watchList.Sort(noteComparer); + _watchList.Reverse(); + } + else + { + _watchList.Sort(noteComparer); + } + + break; + } + } + + /// + /// Sets WatchList's domain list to a new one + /// domain will also be refreshed + /// + /// New domains + public void RefreshDomains(IMemoryDomains core) + { + _memoryDomains = core; + Parallel.ForEach(_watchList, watch => { if (watch.IsSeparator) - return; - watch.Domain = core[watch.Domain.Name]; - watch.ResetPrevious(); - watch.Update(); - watch.ClearChangeCount(); - } - ); - } - - /// - /// Updates all ine the current collection - /// - public void UpdateValues() - { - Parallel.ForEach(_watchList, watch => - { - watch.Update(); - }); - } - - #endregion - - #region Propeties - - #region ICollection - - /// - /// Gets the number of elements contained in this - /// - public int Count - { - get - { - return _watchList.Count; - } - } - - /// - /// is alsways read-write - /// so this value will be always false - /// - public bool IsReadOnly - { - get - { - return false; - } - } - - #endregion ICollection - - #region IList - - /// - /// Gets or sets element at the specified index - /// - /// The zero based index of the element you want to get or set - /// at the specified index - public Watch this[int index] - { - get - { - return _watchList[index]; - } - set - { - _watchList[index] = value; - } - } - - #endregion IList - - /// - /// Gets a value indicating if collection has changed or not - /// - public bool Changes { get; set; } - - /// - /// Gets or sets current 's filename - /// - public string CurrentFileName - { - get - { - return _currentFilename; - } - set - { - _currentFilename = value; - } - } - - /// - /// Gets the number of that are not - /// - public int WatchCount - { - get - { - return _watchList.Count(watch => !watch.IsSeparator); - } - } - - #endregion - - #region File handling logic - probably needs to be its own class - - public bool Load(string path, bool append) - { - var result = LoadFile(path, append); - - if (result) - { - if (append) - { - Changes = true; - } - else - { - CurrentFileName = path; - Changes = false; - } - } - - return result; - } - - public void Reload() - { - if (!string.IsNullOrWhiteSpace(CurrentFileName)) - { - LoadFile(CurrentFileName, append: false); - Changes = false; - } - } - - public bool Save() - { - if (string.IsNullOrWhiteSpace(CurrentFileName)) - { - return false; - } - - using (var sw = new StreamWriter(CurrentFileName)) - { - var sb = new StringBuilder(); - sb.Append("SystemID ").AppendLine(_systemid); - - foreach (var watch in _watchList) - { - sb.AppendLine(watch.ToString()); - } - - sw.WriteLine(sb.ToString()); - } - - Changes = false; - return true; - } - - public bool SaveAs(FileInfo file) - { - if (file != null) - { - CurrentFileName = file.FullName; - return Save(); - } - - return false; - } - - private bool LoadFile(string path, bool append) - { - var file = new FileInfo(path); - if (file.Exists == false) - { - return false; - } - - var isBizHawkWatch = true; // Hack to support .wch files from other emulators - using (var sr = file.OpenText()) - { - string line; - - if (!append) - { - Clear(); - } - - while ((line = sr.ReadLine()) != null) - { - // .wch files from other emulators start with a number representing the number of watch, that line can be discarded here - // Any properly formatted line couldn't possibly be this short anyway, this also takes care of any garbage lines that might be in a file - if (line.Length < 5) - { - isBizHawkWatch = false; - continue; - } - - if (line.Length >= 6 && line.Substring(0, 6) == "Domain") - { - isBizHawkWatch = true; - } - - if (line.Length >= 8 && line.Substring(0, 8) == "SystemID") - { - continue; - } - - var numColumns = line.HowMany('\t'); - int startIndex; - if (numColumns == 5) - { - // If 5, then this is a post 1.0.5 .wch file - if (isBizHawkWatch) - { - // Do nothing here - } - else - { - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // 5 digit value representing the watch position number - } - } - else - { - continue; // If not 4, something is wrong with this line, ignore it - } - - // Temporary, rename if kept - int addr; - var memDomain = _memoryDomains.MainMemory; - - var temp = line.Substring(0, line.IndexOf('\t')); - try - { - addr = int.Parse(temp, NumberStyles.HexNumber); - } - catch - { - continue; - } - - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Type - var size = Watch.SizeFromChar(line[0]); - - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Signed - var type = Watch.DisplayTypeFromChar(line[0]); - - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Endian - try - { - startIndex = short.Parse(line[0].ToString()); - } - catch - { - continue; - } - - var bigEndian = startIndex != 0; - - if (isBizHawkWatch) - { - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Domain - temp = line.Substring(0, line.IndexOf('\t')); - memDomain = _memoryDomains[temp] ?? _memoryDomains.MainMemory; - } - - startIndex = line.IndexOf('\t') + 1; - var notes = line.Substring(startIndex, line.Length - startIndex); - - _watchList.Add( - Watch.GenerateWatch( - memDomain, - addr, - size, - type, - bigEndian, - notes)); - } - - _currentFilename = path; - } - - if (!append) - { - Changes = false; - } - else - { - Changes = true; - } - - return true; - } - #endregion - } -} + return; + watch.Domain = core[watch.Domain.Name]; + watch.ResetPrevious(); + watch.Update(); + watch.ClearChangeCount(); + } + ); + } + + /// + /// Updates all ine the current collection + /// + public void UpdateValues() + { + Parallel.ForEach(_watchList, watch => + { + watch.Update(); + }); + } + + #endregion + + #region Propeties + + #region ICollection + + /// + /// Gets the number of elements contained in this + /// + public int Count + { + get + { + return _watchList.Count; + } + } + + /// + /// is alsways read-write + /// so this value will be always false + /// + public bool IsReadOnly + { + get + { + return false; + } + } + + #endregion ICollection + + #region IList + + /// + /// Gets or sets element at the specified index + /// + /// The zero based index of the element you want to get or set + /// at the specified index + public Watch this[int index] + { + get + { + return _watchList[index]; + } + set + { + _watchList[index] = value; + } + } + + #endregion IList + + /// + /// Gets a value indicating if collection has changed or not + /// + public bool Changes { get; set; } + + /// + /// Gets or sets current 's filename + /// + public string CurrentFileName + { + get + { + return _currentFilename; + } + set + { + _currentFilename = value; + } + } + + /// + /// Gets the number of that are not + /// + public int WatchCount + { + get + { + return _watchList.Count(watch => !watch.IsSeparator); + } + } + + #endregion + + #region File handling logic - probably needs to be its own class + + public bool Load(string path, bool append) + { + var result = LoadFile(path, append); + + if (result) + { + if (append) + { + Changes = true; + } + else + { + CurrentFileName = path; + Changes = false; + } + } + + return result; + } + + public void Reload() + { + if (!string.IsNullOrWhiteSpace(CurrentFileName)) + { + LoadFile(CurrentFileName, append: false); + Changes = false; + } + } + + public bool Save() + { + if (string.IsNullOrWhiteSpace(CurrentFileName)) + { + return false; + } + + using (var sw = new StreamWriter(CurrentFileName)) + { + var sb = new StringBuilder(); + sb.Append("SystemID ").AppendLine(_systemid); + + foreach (var watch in _watchList) + { + sb.AppendLine(watch.ToString()); + } + + sw.WriteLine(sb.ToString()); + } + + Changes = false; + return true; + } + + public bool SaveAs(FileInfo file) + { + if (file != null) + { + CurrentFileName = file.FullName; + return Save(); + } + + return false; + } + + private bool LoadFile(string path, bool append) + { + var file = new FileInfo(path); + if (file.Exists == false) + { + return false; + } + + var isBizHawkWatch = true; // Hack to support .wch files from other emulators + using (var sr = file.OpenText()) + { + string line; + + if (!append) + { + Clear(); + } + + while ((line = sr.ReadLine()) != null) + { + // .wch files from other emulators start with a number representing the number of watch, that line can be discarded here + // Any properly formatted line couldn't possibly be this short anyway, this also takes care of any garbage lines that might be in a file + if (line.Length < 5) + { + isBizHawkWatch = false; + continue; + } + + if (line.Length >= 6 && line.Substring(0, 6) == "Domain") + { + isBizHawkWatch = true; + } + + if (line.Length >= 8 && line.Substring(0, 8) == "SystemID") + { + continue; + } + + var numColumns = line.HowMany('\t'); + int startIndex; + if (numColumns == 5) + { + // If 5, then this is a post 1.0.5 .wch file + if (isBizHawkWatch) + { + // Do nothing here + } + else + { + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // 5 digit value representing the watch position number + } + } + else + { + continue; // If not 4, something is wrong with this line, ignore it + } + + // Temporary, rename if kept + int addr; + var memDomain = _memoryDomains.MainMemory; + + var temp = line.Substring(0, line.IndexOf('\t')); + try + { + addr = int.Parse(temp, NumberStyles.HexNumber); + } + catch + { + continue; + } + + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Type + var size = Watch.SizeFromChar(line[0]); + + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Signed + var type = Watch.DisplayTypeFromChar(line[0]); + + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Endian + try + { + startIndex = short.Parse(line[0].ToString()); + } + catch + { + continue; + } + + var bigEndian = startIndex != 0; + + if (isBizHawkWatch) + { + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Domain + temp = line.Substring(0, line.IndexOf('\t')); + memDomain = _memoryDomains[temp] ?? _memoryDomains.MainMemory; + } + + startIndex = line.IndexOf('\t') + 1; + var notes = line.Substring(startIndex, line.Length - startIndex); + + _watchList.Add( + Watch.GenerateWatch( + memDomain, + addr, + size, + type, + bigEndian, + notes)); + } + + _currentFilename = path; + } + + if (!append) + { + Changes = false; + } + else + { + Changes = true; + } + + return true; + } + #endregion + } +} diff --git a/BizHawk.Client.EmuHawk/AVOut/Quantize/OctreeQuantizer.cs b/BizHawk.Client.EmuHawk/AVOut/Quantize/OctreeQuantizer.cs index 9fada01af0..b679b7f7ef 100644 --- a/BizHawk.Client.EmuHawk/AVOut/Quantize/OctreeQuantizer.cs +++ b/BizHawk.Client.EmuHawk/AVOut/Quantize/OctreeQuantizer.cs @@ -1,583 +1,583 @@ -///////////////////////////////////////////////////////////////////////////////// -// Paint.NET -// Copyright (C) Rick Brewster, Chris Crosetto, Dennis Dietrich, Tom Jackson, -// Michael Kelsey, Brandon Ortiz, Craig Taylor, Chris Trevino, -// and Luke Walker -// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. -// See src/setup/License.rtf for complete licensing and attribution information. -///////////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////////// -// Copied for Paint.NET PCX Plugin -// Copyright (C) Joshua Bell -///////////////////////////////////////////////////////////////////////////////// - +///////////////////////////////////////////////////////////////////////////////// +// Paint.NET +// Copyright (C) Rick Brewster, Chris Crosetto, Dennis Dietrich, Tom Jackson, +// Michael Kelsey, Brandon Ortiz, Craig Taylor, Chris Trevino, +// and Luke Walker +// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. +// See src/setup/License.rtf for complete licensing and attribution information. +///////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////// +// Copied for Paint.NET PCX Plugin +// Copyright (C) Joshua Bell +///////////////////////////////////////////////////////////////////////////////// + // Based on: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/colorquant.asp -//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize - -using System; -using System.Collections.Generic; -using System.Drawing; +//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize + +using System; +using System.Collections.Generic; +using System.Drawing; using System.Drawing.Imaging; -namespace BizHawk.Client.EmuHawk -{ - /// - /// Quantize using an Octree +namespace BizHawk.Client.EmuHawk +{ + /// + /// Quantize using an Octree /// - unsafe class OctreeQuantizer : Quantizer - { - /// - /// Stores the tree - /// - private Octree _octree; - - /// - /// Maximum allowed color depth - /// - private int _maxColors; - - /// - /// Construct the octree quantizer - /// - /// - /// The Octree quantizer is a two pass algorithm. The initial pass sets up the octree, - /// the second pass quantizes a color based on the nodes in the tree - /// - /// The maximum number of colors to return - /// The number of significant bits - public OctreeQuantizer(int maxColors, int maxColorBits) - : base(false) - { - if (maxColors > 255) - throw new ArgumentOutOfRangeException(nameof(maxColors), maxColors, "The number of colors should be less than 256"); - - if ((maxColorBits < 1) |(maxColorBits > 8)) - throw new ArgumentOutOfRangeException(nameof(maxColorBits), maxColorBits, "This should be between 1 and 8"); - - _octree = new Octree(maxColorBits); - _maxColors = maxColors; - } - - /// - /// Process the pixel in the first pass of the algorithm - /// - /// The pixel to quantize - /// - /// This function need only be overridden if your quantize algorithm needs two passes, - /// such as an Octree quantizer. - /// - protected override void InitialQuantizePixel(int pixel) - { - _octree.AddColor(pixel); - } - - /// - /// Override this to process the pixel in the second pass of the algorithm - /// - /// The pixel to quantize + unsafe class OctreeQuantizer : Quantizer + { + /// + /// Stores the tree + /// + private Octree _octree; + + /// + /// Maximum allowed color depth + /// + private int _maxColors; + + /// + /// Construct the octree quantizer + /// + /// + /// The Octree quantizer is a two pass algorithm. The initial pass sets up the octree, + /// the second pass quantizes a color based on the nodes in the tree + /// + /// The maximum number of colors to return + /// The number of significant bits + public OctreeQuantizer(int maxColors, int maxColorBits) + : base(false) + { + if (maxColors > 255) + throw new ArgumentOutOfRangeException(nameof(maxColors), maxColors, "The number of colors should be less than 256"); + + if ((maxColorBits < 1) |(maxColorBits > 8)) + throw new ArgumentOutOfRangeException(nameof(maxColorBits), maxColorBits, "This should be between 1 and 8"); + + _octree = new Octree(maxColorBits); + _maxColors = maxColors; + } + + /// + /// Process the pixel in the first pass of the algorithm + /// + /// The pixel to quantize + /// + /// This function need only be overridden if your quantize algorithm needs two passes, + /// such as an Octree quantizer. + /// + protected override void InitialQuantizePixel(int pixel) + { + _octree.AddColor(pixel); + } + + /// + /// Override this to process the pixel in the second pass of the algorithm + /// + /// The pixel to quantize /// The quantized value - protected override byte QuantizePixel(int pixel) - { - byte paletteIndex = (byte)_maxColors; // The color at [_maxColors] is set to transparent - + protected override byte QuantizePixel(int pixel) + { + byte paletteIndex = (byte)_maxColors; // The color at [_maxColors] is set to transparent + // Get the palette index if this non-transparent int a = (pixel>>24)&0xFF; -#if HANDLE_TRANSPARENCY - if (a > 0) +#if HANDLE_TRANSPARENCY + if (a > 0) #endif - { - paletteIndex = (byte)_octree.GetPaletteIndex(pixel); - } + { + paletteIndex = (byte)_octree.GetPaletteIndex(pixel); + } - return paletteIndex; - } - - /// - /// Retrieve the palette for the quantized image - /// - /// Any old palette, this is overrwritten + return paletteIndex; + } + + /// + /// Retrieve the palette for the quantized image + /// + /// Any old palette, this is overrwritten /// The new color palette - protected override ColorPalette GetPalette(ColorPalette original) - { - // First off convert the octree to _maxColors colors - List palette = _octree.Palletize(_maxColors - 1); - - // Then convert the palette based on those colors - for (int index = 0; index < palette.Count; index++) - { - original.Entries[index] = palette[index]; - } - -#if ORIGINAL_CODE - for (int i = palette.Count; i < original.Entries.Length; ++i) - { - original.Entries[i] = Color.FromArgb(255, 0, 0, 0); - } - - // Add the transparent color - original.Entries[_maxColors] = Color.FromArgb(0, 0, 0, 0); -#else // PCX Plugin - // For PCX: Pad with transparency - for (int i = palette.Count; i < original.Entries.Length; ++i) - original.Entries[i] = Color.Transparent; -#endif - return original; - } - - /// - /// Class which does the actual quantization - /// - private class Octree - { - /// - /// Construct the octree - /// - /// The maximum number of significant bits in the image - public Octree(int maxColorBits) - { - _maxColorBits = maxColorBits; - _leafCount = 0; - _reducibleNodes = new OctreeNode[9]; - _root = new OctreeNode(0, _maxColorBits, this); - _previousColor = 0; - _previousNode = null; - } - - /// - /// Add a given color value to the octree - /// - /// - public void AddColor(int pixel) - { - // Check if this request is for the same color as the last - if (_previousColor == pixel) - { - // If so, check if I have a previous node setup. This will only ocurr if the first color in the image - // happens to be black, with an alpha component of zero. - if (null == _previousNode) - { - _previousColor = pixel; - _root.AddColor(pixel, _maxColorBits, 0, this); - } - else - { - // Just update the previous node - _previousNode.Increment(pixel); - } - } - else + protected override ColorPalette GetPalette(ColorPalette original) + { + // First off convert the octree to _maxColors colors + List palette = _octree.Palletize(_maxColors - 1); + + // Then convert the palette based on those colors + for (int index = 0; index < palette.Count; index++) + { + original.Entries[index] = palette[index]; + } + +#if ORIGINAL_CODE + for (int i = palette.Count; i < original.Entries.Length; ++i) + { + original.Entries[i] = Color.FromArgb(255, 0, 0, 0); + } + + // Add the transparent color + original.Entries[_maxColors] = Color.FromArgb(0, 0, 0, 0); +#else // PCX Plugin + // For PCX: Pad with transparency + for (int i = palette.Count; i < original.Entries.Length; ++i) + original.Entries[i] = Color.Transparent; +#endif + return original; + } + + /// + /// Class which does the actual quantization + /// + private class Octree + { + /// + /// Construct the octree + /// + /// The maximum number of significant bits in the image + public Octree(int maxColorBits) + { + _maxColorBits = maxColorBits; + _leafCount = 0; + _reducibleNodes = new OctreeNode[9]; + _root = new OctreeNode(0, _maxColorBits, this); + _previousColor = 0; + _previousNode = null; + } + + /// + /// Add a given color value to the octree + /// + /// + public void AddColor(int pixel) + { + // Check if this request is for the same color as the last + if (_previousColor == pixel) { - _previousColor = pixel; - _root.AddColor(pixel, _maxColorBits, 0, this); - } - } - - /// - /// Reduce the depth of the tree - /// - public void Reduce() - { - int index; - - // Find the deepest level containing at least one reducible node - for (index = _maxColorBits - 1; (index > 0) && (null == _reducibleNodes[index]); index--) - { - // intentionally blank - } - - // Reduce the node most recently added to the list at level 'index' - OctreeNode node = _reducibleNodes[index]; - _reducibleNodes[index] = node.NextReducible; - - // Decrement the leaf count after reducing the node - _leafCount -= node.Reduce(); - - // And just in case I've reduced the last color to be added, and the next color to - // be added is the same, invalidate the previousNode... - _previousNode = null; - } - - /// - /// Get/Set the number of leaves in the tree - /// - public int Leaves - { - get - { - return _leafCount; - } - - set - { - _leafCount = value; - } - } - - /// - /// Return the array of reducible nodes - /// - protected OctreeNode[] ReducibleNodes - { - get - { - return _reducibleNodes; - } - } - - /// - /// Keep track of the previous node that was quantized - /// - /// The node last quantized - protected void TrackPrevious(OctreeNode node) - { - _previousNode = node; - } - - private Color[] _palette; - private PaletteTable paletteTable; - - /// - /// Convert the nodes in the octree to a palette with a maximum of colorCount colors - /// - /// The maximum number of colors - /// A list with the palettized colors - public List Palletize(int colorCount) - { - while (Leaves > colorCount) - { - Reduce(); - } - - // Now palettize the nodes - List palette = new List(Leaves); - int paletteIndex = 0; - - _root.ConstructPalette(palette, ref paletteIndex); - - // And return the palette - this._palette = palette.ToArray(); - this.paletteTable = null; - - return palette; - } - - /// - /// Get the palette index for the passed color - /// - /// - /// - public int GetPaletteIndex(int pixel) - { - int ret = -1; - - ret = _root.GetPaletteIndex(pixel, 0); - - if (ret < 0) - { - if (this.paletteTable == null) - { - this.paletteTable = new PaletteTable(this._palette); + // If so, check if I have a previous node setup. This will only ocurr if the first color in the image + // happens to be black, with an alpha component of zero. + if (null == _previousNode) + { + _previousColor = pixel; + _root.AddColor(pixel, _maxColorBits, 0, this); + } + else + { + // Just update the previous node + _previousNode.Increment(pixel); + } + } + else + { + _previousColor = pixel; + _root.AddColor(pixel, _maxColorBits, 0, this); + } + } + + /// + /// Reduce the depth of the tree + /// + public void Reduce() + { + int index; + + // Find the deepest level containing at least one reducible node + for (index = _maxColorBits - 1; (index > 0) && (null == _reducibleNodes[index]); index--) + { + // intentionally blank + } + + // Reduce the node most recently added to the list at level 'index' + OctreeNode node = _reducibleNodes[index]; + _reducibleNodes[index] = node.NextReducible; + + // Decrement the leaf count after reducing the node + _leafCount -= node.Reduce(); + + // And just in case I've reduced the last color to be added, and the next color to + // be added is the same, invalidate the previousNode... + _previousNode = null; + } + + /// + /// Get/Set the number of leaves in the tree + /// + public int Leaves + { + get + { + return _leafCount; + } + + set + { + _leafCount = value; + } + } + + /// + /// Return the array of reducible nodes + /// + protected OctreeNode[] ReducibleNodes + { + get + { + return _reducibleNodes; + } + } + + /// + /// Keep track of the previous node that was quantized + /// + /// The node last quantized + protected void TrackPrevious(OctreeNode node) + { + _previousNode = node; + } + + private Color[] _palette; + private PaletteTable paletteTable; + + /// + /// Convert the nodes in the octree to a palette with a maximum of colorCount colors + /// + /// The maximum number of colors + /// A list with the palettized colors + public List Palletize(int colorCount) + { + while (Leaves > colorCount) + { + Reduce(); + } + + // Now palettize the nodes + List palette = new List(Leaves); + int paletteIndex = 0; + + _root.ConstructPalette(palette, ref paletteIndex); + + // And return the palette + this._palette = palette.ToArray(); + this.paletteTable = null; + + return palette; + } + + /// + /// Get the palette index for the passed color + /// + /// + /// + public int GetPaletteIndex(int pixel) + { + int ret = -1; + + ret = _root.GetPaletteIndex(pixel, 0); + + if (ret < 0) + { + if (this.paletteTable == null) + { + this.paletteTable = new PaletteTable(this._palette); } - ret = this.paletteTable.FindClosestPaletteIndex(Color.FromArgb(pixel)); - } - - return ret; - } - - /// - /// Mask used when getting the appropriate pixels for a given node - /// - private static int[] mask = new int[8] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; - - /// - /// The root of the octree - /// - private OctreeNode _root; - - /// - /// Number of leaves in the tree - /// - private int _leafCount; - - /// - /// Array of reducible nodes - /// - private OctreeNode[] _reducibleNodes; - - /// - /// Maximum number of significant bits in the image - /// - private int _maxColorBits; - - /// - /// Store the last node quantized - /// - private OctreeNode _previousNode; - - /// - /// Cache the previous color quantized - /// - private int _previousColor; - - /// - /// Class which encapsulates each node in the tree - /// - protected class OctreeNode - { - /// - /// Construct the node - /// - /// The level in the tree = 0 - 7 - /// The number of significant color bits in the image - /// The tree to which this node belongs - public OctreeNode(int level, int colorBits, Octree octree) - { - // Construct the new node - _leaf = (level == colorBits); - - _red = 0; - _green = 0; - _blue = 0; - _pixelCount = 0; - - // If a leaf, increment the leaf count - if (_leaf) - { - octree.Leaves++; - _nextReducible = null; - _children = null; - } - else - { - // Otherwise add this to the reducible nodes - _nextReducible = octree.ReducibleNodes[level]; - octree.ReducibleNodes[level] = this; - _children = new OctreeNode[8]; - } - } - - /// - /// Add a color into the tree - /// - /// The color - /// The number of significant color bits - /// The level in the tree - /// The tree to which this node belongs - public void AddColor(int pixel, int colorBits, int level, Octree octree) - { - // Update the color information if this is a leaf - if (_leaf) - { - Increment(pixel); - - // Setup the previous node - octree.TrackPrevious(this); - } - else - { - // Go to the next level down in the tree + ret = this.paletteTable.FindClosestPaletteIndex(Color.FromArgb(pixel)); + } + + return ret; + } + + /// + /// Mask used when getting the appropriate pixels for a given node + /// + private static int[] mask = new int[8] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + + /// + /// The root of the octree + /// + private OctreeNode _root; + + /// + /// Number of leaves in the tree + /// + private int _leafCount; + + /// + /// Array of reducible nodes + /// + private OctreeNode[] _reducibleNodes; + + /// + /// Maximum number of significant bits in the image + /// + private int _maxColorBits; + + /// + /// Store the last node quantized + /// + private OctreeNode _previousNode; + + /// + /// Cache the previous color quantized + /// + private int _previousColor; + + /// + /// Class which encapsulates each node in the tree + /// + protected class OctreeNode + { + /// + /// Construct the node + /// + /// The level in the tree = 0 - 7 + /// The number of significant color bits in the image + /// The tree to which this node belongs + public OctreeNode(int level, int colorBits, Octree octree) + { + // Construct the new node + _leaf = (level == colorBits); + + _red = 0; + _green = 0; + _blue = 0; + _pixelCount = 0; + + // If a leaf, increment the leaf count + if (_leaf) + { + octree.Leaves++; + _nextReducible = null; + _children = null; + } + else + { + // Otherwise add this to the reducible nodes + _nextReducible = octree.ReducibleNodes[level]; + octree.ReducibleNodes[level] = this; + _children = new OctreeNode[8]; + } + } + + /// + /// Add a color into the tree + /// + /// The color + /// The number of significant color bits + /// The level in the tree + /// The tree to which this node belongs + public void AddColor(int pixel, int colorBits, int level, Octree octree) + { + // Update the color information if this is a leaf + if (_leaf) + { + Increment(pixel); + + // Setup the previous node + octree.TrackPrevious(this); + } + else + { + // Go to the next level down in the tree int shift = 7 - level; int b = pixel & 0xFF; int g = (pixel >> 8) & 0xFF; - int r = (pixel >> 16) & 0xFF; - int index = ((r & mask[level]) >> (shift - 2)) | - ((g & mask[level]) >> (shift - 1)) | - ((b & mask[level]) >> (shift)); - - OctreeNode child = _children[index]; - - if (null == child) - { - // Create a new child node & store in the array - child = new OctreeNode(level + 1, colorBits, octree); - _children[index] = child; - } - - // Add the color to the child node - child.AddColor(pixel, colorBits, level + 1, octree); - } - - } - - /// - /// Get/Set the next reducible node - /// - public OctreeNode NextReducible - { - get - { - return _nextReducible; - } - - set - { - _nextReducible = value; - } - } - - /// - /// Return the child nodes - /// - public OctreeNode[] Children - { - get - { - return _children; - } - } - - /// - /// Reduce this node by removing all of its children - /// - /// The number of leaves removed - public int Reduce() - { - int children = 0; - _red = 0; - _green = 0; - _blue = 0; - - // Loop through all children and add their information to this node - for (int index = 0; index < 8; index++) - { - if (null != _children[index]) - { - _red += _children[index]._red; - _green += _children[index]._green; - _blue += _children[index]._blue; - _pixelCount += _children[index]._pixelCount; - ++children; - _children[index] = null; - } - } - - // Now change this to a leaf node - _leaf = true; - - // Return the number of nodes to decrement the leaf count by - return(children - 1); - } - - /// - /// Traverse the tree, building up the color palette - /// - /// The palette - /// The current palette index - public void ConstructPalette(List palette, ref int paletteIndex) - { - if (_leaf) - { - // Consume the next palette index - _paletteIndex = paletteIndex++; - - // And set the color of the palette entry - int r = _red / _pixelCount; - int g = _green / _pixelCount; - int b = _blue / _pixelCount; - - palette.Add(Color.FromArgb(r, g, b)); - } - else - { - // Loop through children looking for leaves - for (int index = 0; index < 8; index++) - { - if (null != _children[index]) - { - _children[index].ConstructPalette(palette, ref paletteIndex); - } - } - } - } - - /// - /// Return the palette index for the passed color - /// - public int GetPaletteIndex(int pixel, int level) - { - int paletteIndex = _paletteIndex; - - if (!_leaf) - { + int r = (pixel >> 16) & 0xFF; + int index = ((r & mask[level]) >> (shift - 2)) | + ((g & mask[level]) >> (shift - 1)) | + ((b & mask[level]) >> (shift)); + + OctreeNode child = _children[index]; + + if (null == child) + { + // Create a new child node & store in the array + child = new OctreeNode(level + 1, colorBits, octree); + _children[index] = child; + } + + // Add the color to the child node + child.AddColor(pixel, colorBits, level + 1, octree); + } + + } + + /// + /// Get/Set the next reducible node + /// + public OctreeNode NextReducible + { + get + { + return _nextReducible; + } + + set + { + _nextReducible = value; + } + } + + /// + /// Return the child nodes + /// + public OctreeNode[] Children + { + get + { + return _children; + } + } + + /// + /// Reduce this node by removing all of its children + /// + /// The number of leaves removed + public int Reduce() + { + int children = 0; + _red = 0; + _green = 0; + _blue = 0; + + // Loop through all children and add their information to this node + for (int index = 0; index < 8; index++) + { + if (null != _children[index]) + { + _red += _children[index]._red; + _green += _children[index]._green; + _blue += _children[index]._blue; + _pixelCount += _children[index]._pixelCount; + ++children; + _children[index] = null; + } + } + + // Now change this to a leaf node + _leaf = true; + + // Return the number of nodes to decrement the leaf count by + return(children - 1); + } + + /// + /// Traverse the tree, building up the color palette + /// + /// The palette + /// The current palette index + public void ConstructPalette(List palette, ref int paletteIndex) + { + if (_leaf) + { + // Consume the next palette index + _paletteIndex = paletteIndex++; + + // And set the color of the palette entry + int r = _red / _pixelCount; + int g = _green / _pixelCount; + int b = _blue / _pixelCount; + + palette.Add(Color.FromArgb(r, g, b)); + } + else + { + // Loop through children looking for leaves + for (int index = 0; index < 8; index++) + { + if (null != _children[index]) + { + _children[index].ConstructPalette(palette, ref paletteIndex); + } + } + } + } + + /// + /// Return the palette index for the passed color + /// + public int GetPaletteIndex(int pixel, int level) + { + int paletteIndex = _paletteIndex; + + if (!_leaf) + { int shift = 7 - level; int b = pixel & 0xFF; int g = (pixel >> 8) & 0xFF; - int r = (pixel >> 16) & 0xFF; - int index = ((r & mask[level]) >> (shift - 2)) | - ((g & mask[level]) >> (shift - 1)) | - ((b & mask[level]) >> (shift)); - - if (null != _children[index]) - { - paletteIndex = _children[index].GetPaletteIndex(pixel, level + 1); - } - else - { - paletteIndex = -1; - } - } - - return paletteIndex; - } - - /// - /// Increment the pixel count and add to the color information - /// - public void Increment(int pixel) - { + int r = (pixel >> 16) & 0xFF; + int index = ((r & mask[level]) >> (shift - 2)) | + ((g & mask[level]) >> (shift - 1)) | + ((b & mask[level]) >> (shift)); + + if (null != _children[index]) + { + paletteIndex = _children[index].GetPaletteIndex(pixel, level + 1); + } + else + { + paletteIndex = -1; + } + } + + return paletteIndex; + } + + /// + /// Increment the pixel count and add to the color information + /// + public void Increment(int pixel) + { ++_pixelCount; int b = pixel&0xFF; int g = (pixel>>8) & 0xFF; int r = (pixel >> 16) & 0xFF; _red += r; _green += g; - _blue += b; - } - - /// - /// Flag indicating that this is a leaf node - /// - private bool _leaf; - - /// - /// Number of pixels in this node - /// - private int _pixelCount; - - /// - /// Red component - /// - private int _red; - - /// - /// Green Component - /// - private int _green; - - /// - /// Blue component - /// - private int _blue; - - /// - /// Pointers to any child nodes - /// - private OctreeNode[] _children; - - /// - /// Pointer to next reducible node - /// - private OctreeNode _nextReducible; - - /// - /// The index of this node in the palette - /// - private int _paletteIndex; - } - } - } -} + _blue += b; + } + + /// + /// Flag indicating that this is a leaf node + /// + private bool _leaf; + + /// + /// Number of pixels in this node + /// + private int _pixelCount; + + /// + /// Red component + /// + private int _red; + + /// + /// Green Component + /// + private int _green; + + /// + /// Blue component + /// + private int _blue; + + /// + /// Pointers to any child nodes + /// + private OctreeNode[] _children; + + /// + /// Pointer to next reducible node + /// + private OctreeNode _nextReducible; + + /// + /// The index of this node in the palette + /// + private int _paletteIndex; + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/AVOut/Quantize/PaletteTable.cs b/BizHawk.Client.EmuHawk/AVOut/Quantize/PaletteTable.cs index c85fd5cdcc..367e73319f 100644 --- a/BizHawk.Client.EmuHawk/AVOut/Quantize/PaletteTable.cs +++ b/BizHawk.Client.EmuHawk/AVOut/Quantize/PaletteTable.cs @@ -1,77 +1,77 @@ -///////////////////////////////////////////////////////////////////////////////// -// Paint.NET -// Copyright (C) Rick Brewster, Chris Crosetto, Dennis Dietrich, Tom Jackson, -// Michael Kelsey, Brandon Ortiz, Craig Taylor, Chris Trevino, -// and Luke Walker -// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. -// See src/setup/License.rtf for complete licensing and attribution information. -///////////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////////// -// Copied for Paint.NET PCX Plugin -// Copyright (C) Joshua Bell +///////////////////////////////////////////////////////////////////////////////// +// Paint.NET +// Copyright (C) Rick Brewster, Chris Crosetto, Dennis Dietrich, Tom Jackson, +// Michael Kelsey, Brandon Ortiz, Craig Taylor, Chris Trevino, +// and Luke Walker +// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. +// See src/setup/License.rtf for complete licensing and attribution information. ///////////////////////////////////////////////////////////////////////////////// -//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize - +///////////////////////////////////////////////////////////////////////////////// +// Copied for Paint.NET PCX Plugin +// Copyright (C) Joshua Bell +///////////////////////////////////////////////////////////////////////////////// + +//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize + using System.Drawing; -namespace BizHawk.Client.EmuHawk -{ - public sealed class PaletteTable - { - private Color[] palette; - - public Color this[int index] - { - get - { - return this.palette[index]; - } - - set - { - this.palette[index] = value; - } - } - - private int GetDistanceSquared(Color a, Color b) - { - int dsq = 0; // delta squared - int v; - - v = a.B - b.B; - dsq += v * v; - v = a.G - b.G; - dsq += v * v; - v = a.R - b.R; - dsq += v * v; - - return dsq; - } - - public int FindClosestPaletteIndex(Color pixel) - { - int dsqBest = int.MaxValue; - int ret = 0; - - for (int i = 0; i < this.palette.Length; ++i) - { - int dsq = GetDistanceSquared(this.palette[i], pixel); - - if (dsq < dsqBest) - { - dsqBest = dsq; - ret = i; - } - } - - return ret; - } - - public PaletteTable(Color[] palette) - { - this.palette = (Color[])palette.Clone(); - } - } -} +namespace BizHawk.Client.EmuHawk +{ + public sealed class PaletteTable + { + private Color[] palette; + + public Color this[int index] + { + get + { + return this.palette[index]; + } + + set + { + this.palette[index] = value; + } + } + + private int GetDistanceSquared(Color a, Color b) + { + int dsq = 0; // delta squared + int v; + + v = a.B - b.B; + dsq += v * v; + v = a.G - b.G; + dsq += v * v; + v = a.R - b.R; + dsq += v * v; + + return dsq; + } + + public int FindClosestPaletteIndex(Color pixel) + { + int dsqBest = int.MaxValue; + int ret = 0; + + for (int i = 0; i < this.palette.Length; ++i) + { + int dsq = GetDistanceSquared(this.palette[i], pixel); + + if (dsq < dsqBest) + { + dsqBest = dsq; + ret = i; + } + } + + return ret; + } + + public PaletteTable(Color[] palette) + { + this.palette = (Color[])palette.Clone(); + } + } +} diff --git a/BizHawk.Client.EmuHawk/AVOut/Quantize/Quantizer.cs b/BizHawk.Client.EmuHawk/AVOut/Quantize/Quantizer.cs index 44c05cd6dd..bf92c11e2c 100644 --- a/BizHawk.Client.EmuHawk/AVOut/Quantize/Quantizer.cs +++ b/BizHawk.Client.EmuHawk/AVOut/Quantize/Quantizer.cs @@ -1,186 +1,186 @@ -///////////////////////////////////////////////////////////////////////////////// -// Paint.NET -// Copyright (C) Rick Brewster, Chris Crosetto, Dennis Dietrich, Tom Jackson, -// Michael Kelsey, Brandon Ortiz, Craig Taylor, Chris Trevino, -// and Luke Walker -// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. -// See src/setup/License.rtf for complete licensing and attribution information. -///////////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////////// -// Copied for Paint.NET PCX Plugin -// Copyright (C) Joshua Bell -///////////////////////////////////////////////////////////////////////////////// - +///////////////////////////////////////////////////////////////////////////////// +// Paint.NET +// Copyright (C) Rick Brewster, Chris Crosetto, Dennis Dietrich, Tom Jackson, +// Michael Kelsey, Brandon Ortiz, Craig Taylor, Chris Trevino, +// and Luke Walker +// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. +// See src/setup/License.rtf for complete licensing and attribution information. +///////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////// +// Copied for Paint.NET PCX Plugin +// Copyright (C) Joshua Bell +///////////////////////////////////////////////////////////////////////////////// + // Based on: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/colorquant.asp -//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize - -using System; -using System.Drawing; +//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize + +using System; +using System.Drawing; using System.Drawing.Imaging; -namespace BizHawk.Client.EmuHawk -{ - /// - /// Summary description for Class1. - /// - internal unsafe abstract class Quantizer - { - /// - /// Flag used to indicate whether a single pass or two passes are needed for quantization. - /// - private bool _singlePass; - - protected bool highquality; - public bool HighQuality - { - get - { - return highquality; - } - - set - { - highquality = value; - } - } - - protected int ditherLevel; - public int DitherLevel - { - get - { - return this.ditherLevel; - } - - set - { - this.ditherLevel = value; - } - } - - /// - /// Construct the quantizer - /// - /// If true, the quantization only needs to loop through the source pixels once - /// - /// If you construct this class with a true value for singlePass, then the code will, when quantizing your image, - /// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage' - /// and then 'QuantizeImage'. - /// - public Quantizer(bool singlePass) - { - _singlePass = singlePass; - } - - /// - /// Quantize an image and return the resulting output bitmap - /// - /// The image to quantize - /// A quantized version of the image - public Bitmap Quantize(Image source) - { - // Get the size of the source image - int height = source.Height; - int width = source.Width; - - // And construct a rectangle from these dimensions - Rectangle bounds = new Rectangle(0, 0, width, height); - - // First off take a 32bpp copy of the image - Bitmap copy; - - if (source is Bitmap && source.PixelFormat == PixelFormat.Format32bppArgb) - { - copy = (Bitmap)source; - } - else - { - copy = new Bitmap(width, height, PixelFormat.Format32bppArgb); - - // Now lock the bitmap into memory - using (Graphics g = Graphics.FromImage(copy)) - { - g.PageUnit = GraphicsUnit.Pixel; - - // Draw the source image onto the copy bitmap, - // which will effect a widening as appropriate. - g.DrawImage(source, 0, 0, bounds.Width, bounds.Height); - } - } - - // And construct an 8bpp version - Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed); - - // Define a pointer to the bitmap data - BitmapData sourceData = null; - - try - { - // Get the source image bits and lock into memory - sourceData = copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - - // Call the FirstPass function if not a single pass algorithm. - // For something like an octree quantizer, this will run through - // all image pixels, build a data structure, and create a palette. - if (!_singlePass) - { - FirstPass(sourceData, width, height); - } - - // Then set the color palette on the output bitmap. I'm passing in the current palette - // as there's no way to construct a new, empty palette. - output.Palette = this.GetPalette(output.Palette); - - // Then call the second pass which actually does the conversion - SecondPass(sourceData, output, width, height, bounds); - } - - finally - { - // Ensure that the bits are unlocked - copy.UnlockBits(sourceData); - } - - if (copy != source) - { - copy.Dispose(); - } - - // Last but not least, return the output bitmap - return output; - } - - /// - /// Execute the first pass through the pixels in the image - /// - /// The source data - /// The width in pixels of the image - /// The height in pixels of the image - protected virtual void FirstPass(BitmapData sourceData, int width, int height) - { - // Define the source data pointers. The source row is a byte to - // keep addition of the stride value easier (as this is in bytes) - byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer(); - int* pSourcePixel; - - // Loop through each row - for (int row = 0; row < height; row++) - { - // Set the source pixel to the first pixel in this row - pSourcePixel = (Int32*)pSourceRow; - - // And loop through each column - for (int col = 0; col < width; col++, pSourcePixel++) - { - InitialQuantizePixel(*pSourcePixel); - } - - // Add the stride to the source row - pSourceRow += sourceData.Stride; - - } +namespace BizHawk.Client.EmuHawk +{ + /// + /// Summary description for Class1. + /// + internal unsafe abstract class Quantizer + { + /// + /// Flag used to indicate whether a single pass or two passes are needed for quantization. + /// + private bool _singlePass; + + protected bool highquality; + public bool HighQuality + { + get + { + return highquality; + } + + set + { + highquality = value; + } + } + + protected int ditherLevel; + public int DitherLevel + { + get + { + return this.ditherLevel; + } + + set + { + this.ditherLevel = value; + } + } + + /// + /// Construct the quantizer + /// + /// If true, the quantization only needs to loop through the source pixels once + /// + /// If you construct this class with a true value for singlePass, then the code will, when quantizing your image, + /// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage' + /// and then 'QuantizeImage'. + /// + public Quantizer(bool singlePass) + { + _singlePass = singlePass; + } + + /// + /// Quantize an image and return the resulting output bitmap + /// + /// The image to quantize + /// A quantized version of the image + public Bitmap Quantize(Image source) + { + // Get the size of the source image + int height = source.Height; + int width = source.Width; + + // And construct a rectangle from these dimensions + Rectangle bounds = new Rectangle(0, 0, width, height); + + // First off take a 32bpp copy of the image + Bitmap copy; + + if (source is Bitmap && source.PixelFormat == PixelFormat.Format32bppArgb) + { + copy = (Bitmap)source; + } + else + { + copy = new Bitmap(width, height, PixelFormat.Format32bppArgb); + + // Now lock the bitmap into memory + using (Graphics g = Graphics.FromImage(copy)) + { + g.PageUnit = GraphicsUnit.Pixel; + + // Draw the source image onto the copy bitmap, + // which will effect a widening as appropriate. + g.DrawImage(source, 0, 0, bounds.Width, bounds.Height); + } + } + + // And construct an 8bpp version + Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed); + + // Define a pointer to the bitmap data + BitmapData sourceData = null; + + try + { + // Get the source image bits and lock into memory + sourceData = copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + // Call the FirstPass function if not a single pass algorithm. + // For something like an octree quantizer, this will run through + // all image pixels, build a data structure, and create a palette. + if (!_singlePass) + { + FirstPass(sourceData, width, height); + } + + // Then set the color palette on the output bitmap. I'm passing in the current palette + // as there's no way to construct a new, empty palette. + output.Palette = this.GetPalette(output.Palette); + + // Then call the second pass which actually does the conversion + SecondPass(sourceData, output, width, height, bounds); + } + + finally + { + // Ensure that the bits are unlocked + copy.UnlockBits(sourceData); + } + + if (copy != source) + { + copy.Dispose(); + } + + // Last but not least, return the output bitmap + return output; + } + + /// + /// Execute the first pass through the pixels in the image + /// + /// The source data + /// The width in pixels of the image + /// The height in pixels of the image + protected virtual void FirstPass(BitmapData sourceData, int width, int height) + { + // Define the source data pointers. The source row is a byte to + // keep addition of the stride value easier (as this is in bytes) + byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer(); + int* pSourcePixel; + + // Loop through each row + for (int row = 0; row < height; row++) + { + // Set the source pixel to the first pixel in this row + pSourcePixel = (Int32*)pSourceRow; + + // And loop through each column + for (int col = 0; col < width; col++, pSourcePixel++) + { + InitialQuantizePixel(*pSourcePixel); + } + + // Add the stride to the source row + pSourceRow += sourceData.Stride; + + } } int ClampToByte(int val) @@ -188,80 +188,80 @@ namespace BizHawk.Client.EmuHawk if (val < 0) return 0; else if (val > 255) return 255; else return val; - } - - /// - /// Execute a second pass through the bitmap - /// - /// The source bitmap, locked into memory - /// The output bitmap - /// The width in pixels of the image - /// The height in pixels of the image - /// The bounding rectangle - protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds) - { - BitmapData outputData = null; - Color[] pallete = output.Palette.Entries; - int weight = ditherLevel; - - try - { - // Lock the output bitmap into memory - outputData = output.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); - - // Define the source data pointers. The source row is a byte to - // keep addition of the stride value easier (as this is in bytes) - byte* pSourceRow = (byte *)sourceData.Scan0.ToPointer(); - Int32* pSourcePixel = (Int32 *)pSourceRow; - - // Now define the destination data pointers - byte* pDestinationRow = (byte *)outputData.Scan0.ToPointer(); - byte* pDestinationPixel = pDestinationRow; - - int[] errorThisRowR = new int[width + 1]; - int[] errorThisRowG = new int[width + 1]; - int[] errorThisRowB = new int[width + 1]; - - for (int row = 0; row < height; row++) - { - int[] errorNextRowR = new int[width + 1]; - int[] errorNextRowG = new int[width + 1]; - int[] errorNextRowB = new int[width + 1]; - - int ptrInc; - - if ((row & 1) == 0) - { - pSourcePixel = (Int32*)pSourceRow; - pDestinationPixel = pDestinationRow; - ptrInc = +1; - } - else - { - pSourcePixel = (Int32*)pSourceRow + width - 1; - pDestinationPixel = pDestinationRow + width - 1; - ptrInc = -1; - } - - // Loop through each pixel on this scan line - for (int col = 0; col < width; ++col) - { - // Quantize the pixel + } + + /// + /// Execute a second pass through the bitmap + /// + /// The source bitmap, locked into memory + /// The output bitmap + /// The width in pixels of the image + /// The height in pixels of the image + /// The bounding rectangle + protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds) + { + BitmapData outputData = null; + Color[] pallete = output.Palette.Entries; + int weight = ditherLevel; + + try + { + // Lock the output bitmap into memory + outputData = output.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); + + // Define the source data pointers. The source row is a byte to + // keep addition of the stride value easier (as this is in bytes) + byte* pSourceRow = (byte *)sourceData.Scan0.ToPointer(); + Int32* pSourcePixel = (Int32 *)pSourceRow; + + // Now define the destination data pointers + byte* pDestinationRow = (byte *)outputData.Scan0.ToPointer(); + byte* pDestinationPixel = pDestinationRow; + + int[] errorThisRowR = new int[width + 1]; + int[] errorThisRowG = new int[width + 1]; + int[] errorThisRowB = new int[width + 1]; + + for (int row = 0; row < height; row++) + { + int[] errorNextRowR = new int[width + 1]; + int[] errorNextRowG = new int[width + 1]; + int[] errorNextRowB = new int[width + 1]; + + int ptrInc; + + if ((row & 1) == 0) + { + pSourcePixel = (Int32*)pSourceRow; + pDestinationPixel = pDestinationRow; + ptrInc = +1; + } + else + { + pSourcePixel = (Int32*)pSourceRow + width - 1; + pDestinationPixel = pDestinationRow + width - 1; + ptrInc = -1; + } + + // Loop through each pixel on this scan line + for (int col = 0; col < width; ++col) + { + // Quantize the pixel int srcPixel = *pSourcePixel; int srcR = srcPixel & 0xFF; //not int srcG = (srcPixel>>8) & 0xFF; //a int srcB = (srcPixel>>16) & 0xFF; //mistake - int srcA = (srcPixel >> 24) & 0xFF; - - int targetB = ClampToByte(srcB - ((errorThisRowB[col] * weight) / 8)); - int targetG = ClampToByte(srcG - ((errorThisRowG[col] * weight) / 8)); - int targetR = ClampToByte(srcR - ((errorThisRowR[col] * weight) / 8)); - int targetA = srcA; - - int target = (targetA<<24)|(targetB<<16)|(targetG<<8)|targetR; - - byte pixelValue = QuantizePixel(target); + int srcA = (srcPixel >> 24) & 0xFF; + + int targetB = ClampToByte(srcB - ((errorThisRowB[col] * weight) / 8)); + int targetG = ClampToByte(srcG - ((errorThisRowG[col] * weight) / 8)); + int targetR = ClampToByte(srcR - ((errorThisRowR[col] * weight) / 8)); + int targetA = srcA; + + int target = (targetA<<24)|(targetB<<16)|(targetG<<8)|targetR; + + byte pixelValue = QuantizePixel(target); *pDestinationPixel = pixelValue; int actual = pallete[pixelValue].ToArgb(); @@ -269,104 +269,104 @@ namespace BizHawk.Client.EmuHawk int actualR = actual & 0xFF; int actualG = (actual >> 8) & 0xFF; int actualB = (actual >> 16) & 0xFF; - int errorR = actualR - targetR; - int errorG = actualG - targetG; - int errorB = actualB - targetB; - - // Floyd-Steinberg Error Diffusion: - // a) 7/16 error goes to x+1 - // b) 5/16 error goes to y+1 - // c) 3/16 error goes to x-1,y+1 - // d) 1/16 error goes to x+1,y+1 - - const int a = 7; - const int b = 5; - const int c = 3; - - int errorRa = (errorR * a) / 16; - int errorRb = (errorR * b) / 16; - int errorRc = (errorR * c) / 16; - int errorRd = errorR - errorRa - errorRb - errorRc; - - int errorGa = (errorG * a) / 16; - int errorGb = (errorG * b) / 16; - int errorGc = (errorG * c) / 16; - int errorGd = errorG - errorGa - errorGb - errorGc; - - int errorBa = (errorB * a) / 16; - int errorBb = (errorB * b) / 16; - int errorBc = (errorB * c) / 16; - int errorBd = errorB - errorBa - errorBb - errorBc; - - errorThisRowR[col + 1] += errorRa; - errorThisRowG[col + 1] += errorGa; - errorThisRowB[col + 1] += errorBa; - - errorNextRowR[width - col] += errorRb; - errorNextRowG[width - col] += errorGb; - errorNextRowB[width - col] += errorBb; - - if (col != 0) - { - errorNextRowR[width - (col - 1)] += errorRc; - errorNextRowG[width - (col - 1)] += errorGc; - errorNextRowB[width - (col - 1)] += errorBc; - } - - errorNextRowR[width - (col + 1)] += errorRd; - errorNextRowG[width - (col + 1)] += errorGd; - errorNextRowB[width - (col + 1)] += errorBd; - - unchecked - { - pSourcePixel += ptrInc; - pDestinationPixel += ptrInc; - } - } - - // Add the stride to the source row - pSourceRow += sourceData.Stride; - - // And to the destination row - pDestinationRow += outputData.Stride; - - errorThisRowB = errorNextRowB; - errorThisRowG = errorNextRowG; - errorThisRowR = errorNextRowR; - } - } - - finally - { - // Ensure that I unlock the output bits - output.UnlockBits(outputData); - } - } - - /// - /// Override this to process the pixel in the first pass of the algorithm - /// - /// The pixel to quantize - /// - /// This function need only be overridden if your quantize algorithm needs two passes, - /// such as an Octree quantizer. - /// - protected virtual void InitialQuantizePixel(int pixel) - { - } - - /// - /// Override this to process the pixel in the second pass of the algorithm - /// - /// The pixel to quantize - /// The quantized value - protected abstract byte QuantizePixel(int pixel); - - /// - /// Retrieve the palette for the quantized image - /// - /// Any old palette, this is overrwritten - /// The new color palette - protected abstract ColorPalette GetPalette(ColorPalette original); - } -} + int errorR = actualR - targetR; + int errorG = actualG - targetG; + int errorB = actualB - targetB; + + // Floyd-Steinberg Error Diffusion: + // a) 7/16 error goes to x+1 + // b) 5/16 error goes to y+1 + // c) 3/16 error goes to x-1,y+1 + // d) 1/16 error goes to x+1,y+1 + + const int a = 7; + const int b = 5; + const int c = 3; + + int errorRa = (errorR * a) / 16; + int errorRb = (errorR * b) / 16; + int errorRc = (errorR * c) / 16; + int errorRd = errorR - errorRa - errorRb - errorRc; + + int errorGa = (errorG * a) / 16; + int errorGb = (errorG * b) / 16; + int errorGc = (errorG * c) / 16; + int errorGd = errorG - errorGa - errorGb - errorGc; + + int errorBa = (errorB * a) / 16; + int errorBb = (errorB * b) / 16; + int errorBc = (errorB * c) / 16; + int errorBd = errorB - errorBa - errorBb - errorBc; + + errorThisRowR[col + 1] += errorRa; + errorThisRowG[col + 1] += errorGa; + errorThisRowB[col + 1] += errorBa; + + errorNextRowR[width - col] += errorRb; + errorNextRowG[width - col] += errorGb; + errorNextRowB[width - col] += errorBb; + + if (col != 0) + { + errorNextRowR[width - (col - 1)] += errorRc; + errorNextRowG[width - (col - 1)] += errorGc; + errorNextRowB[width - (col - 1)] += errorBc; + } + + errorNextRowR[width - (col + 1)] += errorRd; + errorNextRowG[width - (col + 1)] += errorGd; + errorNextRowB[width - (col + 1)] += errorBd; + + unchecked + { + pSourcePixel += ptrInc; + pDestinationPixel += ptrInc; + } + } + + // Add the stride to the source row + pSourceRow += sourceData.Stride; + + // And to the destination row + pDestinationRow += outputData.Stride; + + errorThisRowB = errorNextRowB; + errorThisRowG = errorNextRowG; + errorThisRowR = errorNextRowR; + } + } + + finally + { + // Ensure that I unlock the output bits + output.UnlockBits(outputData); + } + } + + /// + /// Override this to process the pixel in the first pass of the algorithm + /// + /// The pixel to quantize + /// + /// This function need only be overridden if your quantize algorithm needs two passes, + /// such as an Octree quantizer. + /// + protected virtual void InitialQuantizePixel(int pixel) + { + } + + /// + /// Override this to process the pixel in the second pass of the algorithm + /// + /// The pixel to quantize + /// The quantized value + protected abstract byte QuantizePixel(int pixel); + + /// + /// Retrieve the palette for the quantized image + /// + /// Any old palette, this is overrwritten + /// The new color palette + protected abstract ColorPalette GetPalette(ColorPalette original); + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/ExceptionBox.cs b/BizHawk.Client.EmuHawk/CustomControls/ExceptionBox.cs index 70bb677e5f..b4353894c4 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ExceptionBox.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ExceptionBox.cs @@ -1,21 +1,21 @@ -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; - -namespace BizHawk.Client.EmuHawk -{ - public partial class ExceptionBox : Form - { - public ExceptionBox(Exception ex) - { - InitializeComponent(); - txtException.Text = ex.ToString(); - timer1.Start(); +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; + +namespace BizHawk.Client.EmuHawk +{ + public partial class ExceptionBox : Form + { + public ExceptionBox(Exception ex) + { + InitializeComponent(); + txtException.Text = ex.ToString(); + timer1.Start(); } public ExceptionBox(string str) @@ -23,70 +23,70 @@ namespace BizHawk.Client.EmuHawk InitializeComponent(); txtException.Text = str; timer1.Start(); - } - - private void btnCopy_Click(object sender, EventArgs e) - { - DoCopy(); - } - - void DoCopy() - { - string txt = txtException.Text; - Clipboard.SetText(txt); - try - { - if (Clipboard.GetText() == txt) - { - lblDone.Text = "Done!"; - lblDone.ForeColor = SystemColors.ControlText; - return; - } - } - catch - { - } - - lblDone.Text = "ERROR!"; - lblDone.ForeColor = SystemColors.ControlText; - } - - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) - { - if (keyData == (Keys.C | Keys.Control)) - { - DoCopy(); - return true; - } - - return false; - } - - private void btnOK_Click(object sender, EventArgs e) - { - Close(); - } - - private void timer1_Tick(object sender, EventArgs e) - { - int a = lblDone.ForeColor.A - 16; - if (a < 0) a = 0; - lblDone.ForeColor = Color.FromArgb(a, lblDone.ForeColor); - } - - //http://stackoverflow.com/questions/2636065/alpha-in-forecolor - class MyLabel : Label - { - protected override void OnPaint(PaintEventArgs e) - { - Rectangle rc = this.ClientRectangle; - StringFormat fmt = new StringFormat(StringFormat.GenericTypographic); - using (var br = new SolidBrush(this.ForeColor)) - { - e.Graphics.DrawString(this.Text, this.Font, br, rc, fmt); - } - } - } - - } -} + } + + private void btnCopy_Click(object sender, EventArgs e) + { + DoCopy(); + } + + void DoCopy() + { + string txt = txtException.Text; + Clipboard.SetText(txt); + try + { + if (Clipboard.GetText() == txt) + { + lblDone.Text = "Done!"; + lblDone.ForeColor = SystemColors.ControlText; + return; + } + } + catch + { + } + + lblDone.Text = "ERROR!"; + lblDone.ForeColor = SystemColors.ControlText; + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == (Keys.C | Keys.Control)) + { + DoCopy(); + return true; + } + + return false; + } + + private void btnOK_Click(object sender, EventArgs e) + { + Close(); + } + + private void timer1_Tick(object sender, EventArgs e) + { + int a = lblDone.ForeColor.A - 16; + if (a < 0) a = 0; + lblDone.ForeColor = Color.FromArgb(a, lblDone.ForeColor); + } + + //http://stackoverflow.com/questions/2636065/alpha-in-forecolor + class MyLabel : Label + { + protected override void OnPaint(PaintEventArgs e) + { + Rectangle rc = this.ClientRectangle; + StringFormat fmt = new StringFormat(StringFormat.GenericTypographic); + using (var br = new SolidBrush(this.ForeColor)) + { + e.Graphics.DrawString(this.Text, this.Font, br, rc, fmt); + } + } + } + + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 1efd3d202f..f5c459fb5d 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -1,627 +1,627 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Windows.Forms; - -namespace BizHawk.Client.EmuHawk -{ - public partial class InputRoll - { - protected override void OnPaint(PaintEventArgs e) - { - using (var LCK = Gdi.LockGraphics(e.Graphics)) - { - Gdi.StartOffScreenBitmap(Width, Height); - - // White Background - Gdi.SetBrush(Color.White); - Gdi.SetSolidPen(Color.White); - Gdi.FillRectangle(0, 0, Width, Height); - - // Lag frame calculations - SetLagFramesArray(); - - var visibleColumns = _columns.VisibleColumns.ToList(); - - if (visibleColumns.Any()) - { - - DrawColumnBg(e, visibleColumns); - DrawColumnText(e, visibleColumns); - } - - //Background - DrawBg(e, visibleColumns); - - //Foreground - DrawData(e, visibleColumns); - - DrawColumnDrag(e); - DrawCellDrag(e); - - Gdi.CopyToScreen(); - Gdi.EndOffScreenBitmap(); - } - } - - protected override void OnPaintBackground(PaintEventArgs pevent) - { - // Do nothing, and this should never be called - } - - private void DrawColumnDrag(PaintEventArgs e) - { - if (_columnDown != null && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) - { - int x1 = _currentX.Value - (_columnDown.Width.Value / 2); - int y1 = _currentY.Value - (CellHeight / 2); - int x2 = x1 + _columnDown.Width.Value; - int y2 = y1 + CellHeight; - - Gdi.SetSolidPen(_backColor); - Gdi.DrawRectangle(x1, y1, x2, y2); - Gdi.PrepDrawString(NormalFont, _foreColor); - Gdi.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); - } - } - - private void DrawCellDrag(PaintEventArgs e) - { - if (DraggingCell != null) - { - var text = ""; - int offsetX = 0; - int offsetY = 0; - if (QueryItemText != null) - { - QueryItemText(DraggingCell.RowIndex.Value, DraggingCell.Column, out text, ref offsetX, ref offsetY); - } - - Color bgColor = _backColor; - if (QueryItemBkColor != null) - { - QueryItemBkColor(DraggingCell.RowIndex.Value, DraggingCell.Column, ref bgColor); - } - - int x1 = _currentX.Value - (DraggingCell.Column.Width.Value / 2); - int y1 = _currentY.Value - (CellHeight / 2); - int x2 = x1 + DraggingCell.Column.Width.Value; - int y2 = y1 + CellHeight; - - - Gdi.SetBrush(bgColor); - Gdi.FillRectangle(x1, y1, x2 - x1, y2 - y1); - Gdi.PrepDrawString(NormalFont, _foreColor); - Gdi.DrawString(text, new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)); - } - } - - private void DrawColumnText(PaintEventArgs e, List visibleColumns) - { - if (HorizontalOrientation) - { - int start = -VBar.Value; - - Gdi.PrepDrawString(NormalFont, _foreColor); - - foreach (var column in visibleColumns) - { - var point = new Point(CellWidthPadding, start + CellHeightPadding); - - if (IsHoveringOnColumnCell && column == CurrentCell.Column) - { - Gdi.PrepDrawString(NormalFont, SystemColors.HighlightText); - Gdi.DrawString(column.Text, point); - Gdi.PrepDrawString(NormalFont, _foreColor); - } - else - { - Gdi.DrawString(column.Text, point); - } - - start += CellHeight; - } - } - else - { - Gdi.PrepDrawString(NormalFont, _foreColor); - - foreach (var column in visibleColumns) - { - var point = new Point(column.Left.Value + 2 * CellWidthPadding - HBar.Value, CellHeightPadding); // TODO: fix this CellPadding issue (2 * CellPadding vs just CellPadding) - - if (IsHoveringOnColumnCell && column == CurrentCell.Column) - { - Gdi.PrepDrawString(NormalFont, SystemColors.HighlightText); - Gdi.DrawString(column.Text, point); - Gdi.PrepDrawString(NormalFont, _foreColor); - } - else - { - Gdi.DrawString(column.Text, point); - } - } - } - } - - private void DrawData(PaintEventArgs e, List visibleColumns) - { - if (QueryItemText != null) - { - if (HorizontalOrientation) - { - int startRow = FirstVisibleRow; - int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - - Gdi.PrepDrawString(NormalFont, _foreColor); - for (int i = 0, f = 0; f < range; i++, f++) - { - f += lagFrames[i]; - int LastVisible = LastVisibleColumnIndex; - for (int j = FirstVisibleColumn; j <= LastVisible; j++) - { - Bitmap image = null; - int x = 0; - int y = 0; - int bitmapOffsetX = 0; - int bitmapOffsetY = 0; - - if (QueryItemIcon != null) - { - QueryItemIcon(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); - } - - if (image != null) - { - x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; - y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; - Gdi.DrawBitmap(image, new Point(x, y), true); - } - - string text; - int strOffsetX = 0; - int strOffsetY = 0; - QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); - - // Center Text - x = RowsToPixels(i) + (CellWidth - text.Length * _charSize.Width) / 2; - y = (j * CellHeight) + CellHeightPadding - VBar.Value; - var point = new Point(x + strOffsetX, y + strOffsetY); - - var rePrep = false; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace BizHawk.Client.EmuHawk +{ + public partial class InputRoll + { + protected override void OnPaint(PaintEventArgs e) + { + using (var LCK = Gdi.LockGraphics(e.Graphics)) + { + Gdi.StartOffScreenBitmap(Width, Height); + + // White Background + Gdi.SetBrush(Color.White); + Gdi.SetSolidPen(Color.White); + Gdi.FillRectangle(0, 0, Width, Height); + + // Lag frame calculations + SetLagFramesArray(); + + var visibleColumns = _columns.VisibleColumns.ToList(); + + if (visibleColumns.Any()) + { + + DrawColumnBg(e, visibleColumns); + DrawColumnText(e, visibleColumns); + } + + //Background + DrawBg(e, visibleColumns); + + //Foreground + DrawData(e, visibleColumns); + + DrawColumnDrag(e); + DrawCellDrag(e); + + Gdi.CopyToScreen(); + Gdi.EndOffScreenBitmap(); + } + } + + protected override void OnPaintBackground(PaintEventArgs pevent) + { + // Do nothing, and this should never be called + } + + private void DrawColumnDrag(PaintEventArgs e) + { + if (_columnDown != null && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) + { + int x1 = _currentX.Value - (_columnDown.Width.Value / 2); + int y1 = _currentY.Value - (CellHeight / 2); + int x2 = x1 + _columnDown.Width.Value; + int y2 = y1 + CellHeight; + + Gdi.SetSolidPen(_backColor); + Gdi.DrawRectangle(x1, y1, x2, y2); + Gdi.PrepDrawString(NormalFont, _foreColor); + Gdi.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); + } + } + + private void DrawCellDrag(PaintEventArgs e) + { + if (DraggingCell != null) + { + var text = ""; + int offsetX = 0; + int offsetY = 0; + if (QueryItemText != null) + { + QueryItemText(DraggingCell.RowIndex.Value, DraggingCell.Column, out text, ref offsetX, ref offsetY); + } + + Color bgColor = _backColor; + if (QueryItemBkColor != null) + { + QueryItemBkColor(DraggingCell.RowIndex.Value, DraggingCell.Column, ref bgColor); + } + + int x1 = _currentX.Value - (DraggingCell.Column.Width.Value / 2); + int y1 = _currentY.Value - (CellHeight / 2); + int x2 = x1 + DraggingCell.Column.Width.Value; + int y2 = y1 + CellHeight; + + + Gdi.SetBrush(bgColor); + Gdi.FillRectangle(x1, y1, x2 - x1, y2 - y1); + Gdi.PrepDrawString(NormalFont, _foreColor); + Gdi.DrawString(text, new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)); + } + } + + private void DrawColumnText(PaintEventArgs e, List visibleColumns) + { + if (HorizontalOrientation) + { + int start = -VBar.Value; + + Gdi.PrepDrawString(NormalFont, _foreColor); + + foreach (var column in visibleColumns) + { + var point = new Point(CellWidthPadding, start + CellHeightPadding); + + if (IsHoveringOnColumnCell && column == CurrentCell.Column) + { + Gdi.PrepDrawString(NormalFont, SystemColors.HighlightText); + Gdi.DrawString(column.Text, point); + Gdi.PrepDrawString(NormalFont, _foreColor); + } + else + { + Gdi.DrawString(column.Text, point); + } + + start += CellHeight; + } + } + else + { + Gdi.PrepDrawString(NormalFont, _foreColor); + + foreach (var column in visibleColumns) + { + var point = new Point(column.Left.Value + 2 * CellWidthPadding - HBar.Value, CellHeightPadding); // TODO: fix this CellPadding issue (2 * CellPadding vs just CellPadding) + + if (IsHoveringOnColumnCell && column == CurrentCell.Column) + { + Gdi.PrepDrawString(NormalFont, SystemColors.HighlightText); + Gdi.DrawString(column.Text, point); + Gdi.PrepDrawString(NormalFont, _foreColor); + } + else + { + Gdi.DrawString(column.Text, point); + } + } + } + } + + private void DrawData(PaintEventArgs e, List visibleColumns) + { + if (QueryItemText != null) + { + if (HorizontalOrientation) + { + int startRow = FirstVisibleRow; + int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; + + Gdi.PrepDrawString(NormalFont, _foreColor); + for (int i = 0, f = 0; f < range; i++, f++) + { + f += lagFrames[i]; + int LastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= LastVisible; j++) + { + Bitmap image = null; + int x = 0; + int y = 0; + int bitmapOffsetX = 0; + int bitmapOffsetY = 0; + + if (QueryItemIcon != null) + { + QueryItemIcon(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); + } + + if (image != null) + { + x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; + y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; + Gdi.DrawBitmap(image, new Point(x, y), true); + } + + string text; + int strOffsetX = 0; + int strOffsetY = 0; + QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); + + // Center Text + x = RowsToPixels(i) + (CellWidth - text.Length * _charSize.Width) / 2; + y = (j * CellHeight) + CellHeightPadding - VBar.Value; + var point = new Point(x + strOffsetX, y + strOffsetY); + + var rePrep = false; if(j==1) - if (SelectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = i + startRow })) - { - Gdi.PrepDrawString(RotatedFont, SystemColors.HighlightText); - rePrep = true; + if (SelectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = i + startRow })) + { + Gdi.PrepDrawString(RotatedFont, SystemColors.HighlightText); + rePrep = true; } else if (j == 1) { //1. not sure about this; 2. repreps may be excess, but if we render one column at a time, we do need to change back after rendering the header rePrep = true; Gdi.PrepDrawString(RotatedFont, _foreColor); - } - - - - if (!string.IsNullOrWhiteSpace(text)) + } + + + + if (!string.IsNullOrWhiteSpace(text)) { - Gdi.DrawString(text, point); - } - - if (rePrep) - { - Gdi.PrepDrawString(NormalFont, _foreColor); - } - } - } - } - else - { - int startRow = FirstVisibleRow; - int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - - Gdi.PrepDrawString(NormalFont, _foreColor); - int xPadding = CellWidthPadding + 1 - HBar.Value; - for (int i = 0, f = 0; f < range; i++, f++) // Vertical - { - f += lagFrames[i]; - int LastVisible = LastVisibleColumnIndex; - for (int j = FirstVisibleColumn; j <= LastVisible; j++) // Horizontal - { - RollColumn col = visibleColumns[j]; - - string text; - int strOffsetX = 0; - int strOffsetY = 0; - Point point = new Point(col.Left.Value + xPadding, RowsToPixels(i) + CellHeightPadding); - - Bitmap image = null; - int bitmapOffsetX = 0; - int bitmapOffsetY = 0; - - if (QueryItemIcon != null) - { - QueryItemIcon(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); - } - - if (image != null) - { - Gdi.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding), true); - } - - QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); - - bool rePrep = false; - if (SelectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = f + startRow })) - { - Gdi.PrepDrawString(NormalFont, SystemColors.HighlightText); - rePrep = true; - } - - if (!string.IsNullOrWhiteSpace(text)) - { - Gdi.DrawString(text, new Point(point.X + strOffsetX, point.Y + strOffsetY)); - } - - if (rePrep) - { - Gdi.PrepDrawString(NormalFont, _foreColor); - } - } - } - } - } - } - - private void DrawColumnBg(PaintEventArgs e, List visibleColumns) - { - Gdi.SetBrush(SystemColors.ControlLight); - Gdi.SetSolidPen(Color.Black); - - if (HorizontalOrientation) - { - Gdi.FillRectangle(0, 0, ColumnWidth + 1, DrawHeight + 1); - Gdi.Line(0, 0, 0, visibleColumns.Count * CellHeight + 1); - Gdi.Line(ColumnWidth, 0, ColumnWidth, visibleColumns.Count * CellHeight + 1); - - int start = -VBar.Value; - foreach (var column in visibleColumns) - { - Gdi.Line(1, start, ColumnWidth, start); - start += CellHeight; - } - - if (visibleColumns.Any()) - { - Gdi.Line(1, start, ColumnWidth, start); - } - } - else - { - int bottomEdge = RowsToPixels(0); - - // Gray column box and black line underneath - Gdi.FillRectangle(0, 0, Width + 1, bottomEdge + 1); - Gdi.Line(0, 0, TotalColWidth.Value + 1, 0); - Gdi.Line(0, bottomEdge, TotalColWidth.Value + 1, bottomEdge); - - // Vertical black seperators - for (int i = 0; i < visibleColumns.Count; i++) - { - int pos = visibleColumns[i].Left.Value - HBar.Value; - Gdi.Line(pos, 0, pos, bottomEdge); - } - - // Draw right most line - if (visibleColumns.Any()) - { - int right = TotalColWidth.Value - HBar.Value; - Gdi.Line(right, 0, right, bottomEdge); - } - } - - // Emphasis - foreach (var column in visibleColumns.Where(c => c.Emphasis)) - { - Gdi.SetBrush(SystemColors.ActiveBorder); - if (HorizontalOrientation) - { - Gdi.FillRectangle(1, visibleColumns.IndexOf(column) * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); - } - else - { - Gdi.FillRectangle(column.Left.Value + 1 - HBar.Value, 1, column.Width.Value - 1, ColumnHeight - 1); - } - } - - // If the user is hovering over a column - if (IsHoveringOnColumnCell) - { - if (HorizontalOrientation) - { - for (int i = 0; i < visibleColumns.Count; i++) - { - if (visibleColumns[i] != CurrentCell.Column) - { - continue; - } - - if (CurrentCell.Column.Emphasis) - { - Gdi.SetBrush(Add(SystemColors.Highlight, 0x00222222)); - } - else - { - Gdi.SetBrush(SystemColors.Highlight); - } - - Gdi.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); - } - } - else - { - //TODO multiple selected columns - for (int i = 0; i < visibleColumns.Count; i++) - { - if (visibleColumns[i] == CurrentCell.Column) - { - //Left of column is to the right of the viewable area or right of column is to the left of the viewable area - if (visibleColumns[i].Left.Value - HBar.Value > Width || visibleColumns[i].Right.Value - HBar.Value < 0) - { - continue; - } - int left = visibleColumns[i].Left.Value - HBar.Value; - int width = visibleColumns[i].Right.Value - HBar.Value - left; - - if (CurrentCell.Column.Emphasis) - { - Gdi.SetBrush(Add(SystemColors.Highlight, 0x00550000)); - } - else - { - Gdi.SetBrush(SystemColors.Highlight); - } - - Gdi.FillRectangle(left + 1, 1, width - 1, ColumnHeight - 1); - } - } - } - } - } - - // TODO refactor this and DoBackGroundCallback functions. - /// - /// Draw Gridlines and background colors using QueryItemBkColor. - /// - /// - private void DrawBg(PaintEventArgs e, List visibleColumns) - { - if (UseCustomBackground && QueryItemBkColor != null) - { - DoBackGroundCallback(e, visibleColumns); - } - - if (GridLines) - { - Gdi.SetSolidPen(SystemColors.ControlLight); - if (HorizontalOrientation) - { - // Columns - for (int i = 1; i < VisibleRows + 1; i++) - { - int x = RowsToPixels(i); - Gdi.Line(x, 1, x, DrawHeight); - } - - // Rows - for (int i = 0; i < visibleColumns.Count + 1; i++) - { - Gdi.Line(RowsToPixels(0) + 1, i * CellHeight - VBar.Value, DrawWidth, i * CellHeight - VBar.Value); - } - } - else - { - // Columns - int y = ColumnHeight + 1; - int? totalColWidth = TotalColWidth; - foreach (var column in visibleColumns) - { - int x = column.Left.Value - HBar.Value; - Gdi.Line(x, y, x, Height - 1); - } - - if (visibleColumns.Any()) - { - Gdi.Line(totalColWidth.Value - HBar.Value, y, totalColWidth.Value - HBar.Value, Height - 1); - } - - // Rows - for (int i = 1; i < VisibleRows + 1; i++) - { - Gdi.Line(0, RowsToPixels(i), Width + 1, RowsToPixels(i)); - } - } - } - - if (SelectedItems.Any()) - { - DoSelectionBG(e, visibleColumns); - } - } - - private void DoSelectionBG(PaintEventArgs e, List visibleColumns) - { - // SuuperW: This allows user to see other colors in selected frames. - Color rowColor = Color.White; - int _lastVisibleRow = LastVisibleRow; - int lastRow = -1; - foreach (Cell cell in SelectedItems) + Gdi.DrawString(text, point); + } + + if (rePrep) + { + Gdi.PrepDrawString(NormalFont, _foreColor); + } + } + } + } + else + { + int startRow = FirstVisibleRow; + int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; + + Gdi.PrepDrawString(NormalFont, _foreColor); + int xPadding = CellWidthPadding + 1 - HBar.Value; + for (int i = 0, f = 0; f < range; i++, f++) // Vertical + { + f += lagFrames[i]; + int LastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= LastVisible; j++) // Horizontal + { + RollColumn col = visibleColumns[j]; + + string text; + int strOffsetX = 0; + int strOffsetY = 0; + Point point = new Point(col.Left.Value + xPadding, RowsToPixels(i) + CellHeightPadding); + + Bitmap image = null; + int bitmapOffsetX = 0; + int bitmapOffsetY = 0; + + if (QueryItemIcon != null) + { + QueryItemIcon(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); + } + + if (image != null) + { + Gdi.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding), true); + } + + QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); + + bool rePrep = false; + if (SelectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = f + startRow })) + { + Gdi.PrepDrawString(NormalFont, SystemColors.HighlightText); + rePrep = true; + } + + if (!string.IsNullOrWhiteSpace(text)) + { + Gdi.DrawString(text, new Point(point.X + strOffsetX, point.Y + strOffsetY)); + } + + if (rePrep) + { + Gdi.PrepDrawString(NormalFont, _foreColor); + } + } + } + } + } + } + + private void DrawColumnBg(PaintEventArgs e, List visibleColumns) + { + Gdi.SetBrush(SystemColors.ControlLight); + Gdi.SetSolidPen(Color.Black); + + if (HorizontalOrientation) + { + Gdi.FillRectangle(0, 0, ColumnWidth + 1, DrawHeight + 1); + Gdi.Line(0, 0, 0, visibleColumns.Count * CellHeight + 1); + Gdi.Line(ColumnWidth, 0, ColumnWidth, visibleColumns.Count * CellHeight + 1); + + int start = -VBar.Value; + foreach (var column in visibleColumns) + { + Gdi.Line(1, start, ColumnWidth, start); + start += CellHeight; + } + + if (visibleColumns.Any()) + { + Gdi.Line(1, start, ColumnWidth, start); + } + } + else + { + int bottomEdge = RowsToPixels(0); + + // Gray column box and black line underneath + Gdi.FillRectangle(0, 0, Width + 1, bottomEdge + 1); + Gdi.Line(0, 0, TotalColWidth.Value + 1, 0); + Gdi.Line(0, bottomEdge, TotalColWidth.Value + 1, bottomEdge); + + // Vertical black seperators + for (int i = 0; i < visibleColumns.Count; i++) + { + int pos = visibleColumns[i].Left.Value - HBar.Value; + Gdi.Line(pos, 0, pos, bottomEdge); + } + + // Draw right most line + if (visibleColumns.Any()) + { + int right = TotalColWidth.Value - HBar.Value; + Gdi.Line(right, 0, right, bottomEdge); + } + } + + // Emphasis + foreach (var column in visibleColumns.Where(c => c.Emphasis)) + { + Gdi.SetBrush(SystemColors.ActiveBorder); + if (HorizontalOrientation) + { + Gdi.FillRectangle(1, visibleColumns.IndexOf(column) * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + } + else + { + Gdi.FillRectangle(column.Left.Value + 1 - HBar.Value, 1, column.Width.Value - 1, ColumnHeight - 1); + } + } + + // If the user is hovering over a column + if (IsHoveringOnColumnCell) + { + if (HorizontalOrientation) + { + for (int i = 0; i < visibleColumns.Count; i++) + { + if (visibleColumns[i] != CurrentCell.Column) + { + continue; + } + + if (CurrentCell.Column.Emphasis) + { + Gdi.SetBrush(Add(SystemColors.Highlight, 0x00222222)); + } + else + { + Gdi.SetBrush(SystemColors.Highlight); + } + + Gdi.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + } + } + else + { + //TODO multiple selected columns + for (int i = 0; i < visibleColumns.Count; i++) + { + if (visibleColumns[i] == CurrentCell.Column) + { + //Left of column is to the right of the viewable area or right of column is to the left of the viewable area + if (visibleColumns[i].Left.Value - HBar.Value > Width || visibleColumns[i].Right.Value - HBar.Value < 0) + { + continue; + } + int left = visibleColumns[i].Left.Value - HBar.Value; + int width = visibleColumns[i].Right.Value - HBar.Value - left; + + if (CurrentCell.Column.Emphasis) + { + Gdi.SetBrush(Add(SystemColors.Highlight, 0x00550000)); + } + else + { + Gdi.SetBrush(SystemColors.Highlight); + } + + Gdi.FillRectangle(left + 1, 1, width - 1, ColumnHeight - 1); + } + } + } + } + } + + // TODO refactor this and DoBackGroundCallback functions. + /// + /// Draw Gridlines and background colors using QueryItemBkColor. + /// + /// + private void DrawBg(PaintEventArgs e, List visibleColumns) + { + if (UseCustomBackground && QueryItemBkColor != null) + { + DoBackGroundCallback(e, visibleColumns); + } + + if (GridLines) + { + Gdi.SetSolidPen(SystemColors.ControlLight); + if (HorizontalOrientation) + { + // Columns + for (int i = 1; i < VisibleRows + 1; i++) + { + int x = RowsToPixels(i); + Gdi.Line(x, 1, x, DrawHeight); + } + + // Rows + for (int i = 0; i < visibleColumns.Count + 1; i++) + { + Gdi.Line(RowsToPixels(0) + 1, i * CellHeight - VBar.Value, DrawWidth, i * CellHeight - VBar.Value); + } + } + else + { + // Columns + int y = ColumnHeight + 1; + int? totalColWidth = TotalColWidth; + foreach (var column in visibleColumns) + { + int x = column.Left.Value - HBar.Value; + Gdi.Line(x, y, x, Height - 1); + } + + if (visibleColumns.Any()) + { + Gdi.Line(totalColWidth.Value - HBar.Value, y, totalColWidth.Value - HBar.Value, Height - 1); + } + + // Rows + for (int i = 1; i < VisibleRows + 1; i++) + { + Gdi.Line(0, RowsToPixels(i), Width + 1, RowsToPixels(i)); + } + } + } + + if (SelectedItems.Any()) + { + DoSelectionBG(e, visibleColumns); + } + } + + private void DoSelectionBG(PaintEventArgs e, List visibleColumns) + { + // SuuperW: This allows user to see other colors in selected frames. + Color rowColor = Color.White; + int _lastVisibleRow = LastVisibleRow; + int lastRow = -1; + foreach (Cell cell in SelectedItems) { if (cell.RowIndex > _lastVisibleRow || cell.RowIndex < FirstVisibleRow || !VisibleColumns.Contains(cell.Column)) continue; - - Cell relativeCell = new Cell - { - RowIndex = cell.RowIndex - FirstVisibleRow, - Column = cell.Column, - }; - relativeCell.RowIndex -= CountLagFramesAbsolute(relativeCell.RowIndex.Value); - - if (QueryRowBkColor != null && lastRow != cell.RowIndex.Value) - { - QueryRowBkColor(cell.RowIndex.Value, ref rowColor); - lastRow = cell.RowIndex.Value; - } - - Color cellColor = rowColor; - QueryItemBkColor(cell.RowIndex.Value, cell.Column, ref cellColor); - // Alpha layering for cell before selection - float alpha = (float)cellColor.A / 255; - if (cellColor.A != 255 && cellColor.A != 0) - { - cellColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - cellColor.R) * alpha), - rowColor.G - (int)((rowColor.G - cellColor.G) * alpha), - rowColor.B - (int)((rowColor.B - cellColor.B) * alpha)); - } - // Alpha layering for selection - alpha = 0.33f; - cellColor = Color.FromArgb(cellColor.R - (int)((cellColor.R - SystemColors.Highlight.R) * alpha), - cellColor.G - (int)((cellColor.G - SystemColors.Highlight.G) * alpha), - cellColor.B - (int)((cellColor.B - SystemColors.Highlight.B) * alpha)); - DrawCellBG(cellColor, relativeCell, visibleColumns); - } - } - - /// - /// Given a cell with rowindex inbetween 0 and VisibleRows, it draws the background color specified. Do not call with absolute rowindices. - /// - private void DrawCellBG(Color color, Cell cell, List visibleColumns) - { - int x, y, w, h; - - if (HorizontalOrientation) - { - x = RowsToPixels(cell.RowIndex.Value) + 1; - w = CellWidth - 1; - y = (CellHeight * visibleColumns.IndexOf(cell.Column)) + 1 - VBar.Value; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = CellHeight - 1; - if (x < ColumnWidth) { return; } - } - else - { - w = cell.Column.Width.Value - 1; - x = cell.Column.Left.Value - HBar.Value + 1; - y = RowsToPixels(cell.RowIndex.Value) + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = CellHeight - 1; - if (y < ColumnHeight) - { - return; - } - } - - if (x > DrawWidth || y > DrawHeight) - { - return; - } // Don't draw if off screen. - - Gdi.SetBrush(color); - Gdi.FillRectangle(x, y, w, h); - } - - /// - /// Calls QueryItemBkColor callback for all visible cells and fills in the background of those cells. - /// - /// - private void DoBackGroundCallback(PaintEventArgs e, List visibleColumns) - { - int startIndex = FirstVisibleRow; - int range = Math.Min(LastVisibleRow, RowCount - 1) - startIndex + 1; - int lastVisible = LastVisibleColumnIndex; - int firstVisibleColumn = FirstVisibleColumn; - if (HorizontalOrientation) - { - for (int i = 0, f = 0; f < range; i++, f++) - { - f += lagFrames[i]; - - Color rowColor = Color.White; - if (QueryRowBkColor != null) - { - QueryRowBkColor(f + startIndex, ref rowColor); - } - - for (int j = firstVisibleColumn; j <= lastVisible; j++) - { - Color itemColor = Color.White; - QueryItemBkColor(f + startIndex, visibleColumns[j], ref itemColor); - if (itemColor == Color.White) - { - itemColor = rowColor; - } - - else if (itemColor.A != 255 && itemColor.A != 0) - { - float alpha = (float)itemColor.A / 255; - itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), - rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), - rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); - } - - if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default - { - var cell = new Cell - { - Column = visibleColumns[j], - RowIndex = i - }; - DrawCellBG(itemColor, cell, visibleColumns); - } - } - } - } - else - { - for (int i = 0, f = 0; f < range; i++, f++) // Vertical - { - f += lagFrames[i]; - - Color rowColor = Color.White; - if (QueryRowBkColor != null) - { - QueryRowBkColor(f + startIndex, ref rowColor); - } - - for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal - { - Color itemColor = Color.White; - QueryItemBkColor(f + startIndex, visibleColumns[j], ref itemColor); - if (itemColor == Color.White) - { - itemColor = rowColor; - } - else if (itemColor.A != 255 && itemColor.A != 0) - { - float alpha = (float)itemColor.A / 255; - itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), - rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), - rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); - } - - if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default - { - var cell = new Cell - { - Column = visibleColumns[j], - RowIndex = i - }; - DrawCellBG(itemColor, cell, visibleColumns); - } - } - } - } - } - } -} + + Cell relativeCell = new Cell + { + RowIndex = cell.RowIndex - FirstVisibleRow, + Column = cell.Column, + }; + relativeCell.RowIndex -= CountLagFramesAbsolute(relativeCell.RowIndex.Value); + + if (QueryRowBkColor != null && lastRow != cell.RowIndex.Value) + { + QueryRowBkColor(cell.RowIndex.Value, ref rowColor); + lastRow = cell.RowIndex.Value; + } + + Color cellColor = rowColor; + QueryItemBkColor(cell.RowIndex.Value, cell.Column, ref cellColor); + // Alpha layering for cell before selection + float alpha = (float)cellColor.A / 255; + if (cellColor.A != 255 && cellColor.A != 0) + { + cellColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - cellColor.R) * alpha), + rowColor.G - (int)((rowColor.G - cellColor.G) * alpha), + rowColor.B - (int)((rowColor.B - cellColor.B) * alpha)); + } + // Alpha layering for selection + alpha = 0.33f; + cellColor = Color.FromArgb(cellColor.R - (int)((cellColor.R - SystemColors.Highlight.R) * alpha), + cellColor.G - (int)((cellColor.G - SystemColors.Highlight.G) * alpha), + cellColor.B - (int)((cellColor.B - SystemColors.Highlight.B) * alpha)); + DrawCellBG(cellColor, relativeCell, visibleColumns); + } + } + + /// + /// Given a cell with rowindex inbetween 0 and VisibleRows, it draws the background color specified. Do not call with absolute rowindices. + /// + private void DrawCellBG(Color color, Cell cell, List visibleColumns) + { + int x, y, w, h; + + if (HorizontalOrientation) + { + x = RowsToPixels(cell.RowIndex.Value) + 1; + w = CellWidth - 1; + y = (CellHeight * visibleColumns.IndexOf(cell.Column)) + 1 - VBar.Value; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't + h = CellHeight - 1; + if (x < ColumnWidth) { return; } + } + else + { + w = cell.Column.Width.Value - 1; + x = cell.Column.Left.Value - HBar.Value + 1; + y = RowsToPixels(cell.RowIndex.Value) + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't + h = CellHeight - 1; + if (y < ColumnHeight) + { + return; + } + } + + if (x > DrawWidth || y > DrawHeight) + { + return; + } // Don't draw if off screen. + + Gdi.SetBrush(color); + Gdi.FillRectangle(x, y, w, h); + } + + /// + /// Calls QueryItemBkColor callback for all visible cells and fills in the background of those cells. + /// + /// + private void DoBackGroundCallback(PaintEventArgs e, List visibleColumns) + { + int startIndex = FirstVisibleRow; + int range = Math.Min(LastVisibleRow, RowCount - 1) - startIndex + 1; + int lastVisible = LastVisibleColumnIndex; + int firstVisibleColumn = FirstVisibleColumn; + if (HorizontalOrientation) + { + for (int i = 0, f = 0; f < range; i++, f++) + { + f += lagFrames[i]; + + Color rowColor = Color.White; + if (QueryRowBkColor != null) + { + QueryRowBkColor(f + startIndex, ref rowColor); + } + + for (int j = firstVisibleColumn; j <= lastVisible; j++) + { + Color itemColor = Color.White; + QueryItemBkColor(f + startIndex, visibleColumns[j], ref itemColor); + if (itemColor == Color.White) + { + itemColor = rowColor; + } + + else if (itemColor.A != 255 && itemColor.A != 0) + { + float alpha = (float)itemColor.A / 255; + itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), + rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), + rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); + } + + if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default + { + var cell = new Cell + { + Column = visibleColumns[j], + RowIndex = i + }; + DrawCellBG(itemColor, cell, visibleColumns); + } + } + } + } + else + { + for (int i = 0, f = 0; f < range; i++, f++) // Vertical + { + f += lagFrames[i]; + + Color rowColor = Color.White; + if (QueryRowBkColor != null) + { + QueryRowBkColor(f + startIndex, ref rowColor); + } + + for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal + { + Color itemColor = Color.White; + QueryItemBkColor(f + startIndex, visibleColumns[j], ref itemColor); + if (itemColor == Color.White) + { + itemColor = rowColor; + } + else if (itemColor.A != 255 && itemColor.A != 0) + { + float alpha = (float)itemColor.A / 255; + itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), + rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), + rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); + } + + if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default + { + var cell = new Cell + { + Column = visibleColumns[j], + RowIndex = i + }; + DrawCellBG(itemColor, cell, visibleColumns); + } + } + } + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/FileLoader.cs b/BizHawk.Client.EmuHawk/FileLoader.cs index f6e210fe3d..1e7224bfb4 100644 --- a/BizHawk.Client.EmuHawk/FileLoader.cs +++ b/BizHawk.Client.EmuHawk/FileLoader.cs @@ -1,351 +1,351 @@ -using System; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using System.Reflection; -using System.Linq; +using System; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using System.Reflection; +using System.Linq; using System.Collections.Generic; -using BizHawk.Common; - -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Emulation.Cores.Calculators; -using BizHawk.Emulation.Cores.ColecoVision; -using BizHawk.Emulation.Cores.Nintendo.Gameboy; -using BizHawk.Emulation.Cores.Nintendo.NES; -using BizHawk.Emulation.Cores.Nintendo.N64; -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.Common; - -using BizHawk.Client.EmuHawk.CustomControls; -using BizHawk.Client.EmuHawk.WinFormExtensions; -using BizHawk.Client.EmuHawk.ToolExtensions; -using BizHawk.Emulation.Cores.Computers.AppleII; -using BizHawk.Client.ApiHawk; - -namespace BizHawk.Client.EmuHawk -{ - partial class MainForm - { - private enum LoadOrdering - { - ROM, - STATE, - WATCH, - CDLFILE, - LUASESSION, - LUASCRIPT, - CHEAT, - MOVIEFILE, - LEGACYMOVIEFILE - } - - public struct FileInformation - { - public string directoryName; - public string fileName; - public string archiveName; - - public FileInformation(string directory, string file, string archive) - { - directoryName = directory; - fileName = file; - archiveName = archive; - } - } - - // This is the list from MainForm->RomFilter()'s non-developer build. It needs to be kept up-to-date when new cores are added. - readonly string[] knownROMExtensions = { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF" }; - readonly string[] nonArchive = { ".ISO", ".CUE", ".CCD" }; - - #region Loaders - - // According to the documentation (http://tasvideos.org/Bizhawk/CodeDataLogger.html), - // Currently supported for: PCE, GB/GBC, SMS/GG, Genesis, SNES - // Perhaps the 'is PCEngine' requirement needs to be expanded. - private void _LoadCDL(string filename, string archive = null) - { - if (!(Global.Emulator is PCEngine)) - return; - - GlobalWin.Tools.Load(); - (GlobalWin.Tools.Get() as CDL).LoadFile(filename); - } - - private void _LoadCheats(string filename, string archive = null) - { - Global.CheatList.Load(filename, false); - GlobalWin.Tools.Load(); - } - - private void _LoadLegacyMovie(string filename, string archive = null) - { - if (Global.Emulator.IsNull()) - { - OpenRom(); - } - - if (Global.Emulator.IsNull()) - { - return; - } - - // tries to open a legacy movie format by importing it - string errorMsg; - string warningMsg; - var movie = MovieImport.ImportFile(filename, out errorMsg, out warningMsg); - if (!string.IsNullOrEmpty(errorMsg)) - { - MessageBox.Show(errorMsg, "Conversion error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else - { - // fix movie extension to something palatable for these purposes. - // for instance, something which doesnt clobber movies you already may have had. - // i'm evenly torn between this, and a file in %TEMP%, but since we dont really have a way to clean up this tempfile, i choose this: - StartNewMovie(movie, false); - } - - GlobalWin.OSD.AddMessage(warningMsg); - } - - private void _LoadLuaFile(string filename, string archive = null) - { - OpenLuaConsole(); - if (GlobalWin.Tools.Has()) - { - GlobalWin.Tools.LuaConsole.LoadLuaFile(filename); - } - } - - private void _LoadLuaSession(string filename, string archive = null) - { - OpenLuaConsole(); - if (GlobalWin.Tools.Has()) - { - GlobalWin.Tools.LuaConsole.LoadLuaSession(filename); - } - } - - private void _LoadMovie(string filename, string archive = null) - { - if (Global.Emulator.IsNull()) - { - OpenRom(); - } - - if (Global.Emulator.IsNull()) - { - return; - } - - StartNewMovie(MovieService.Get(filename), false); - } - - private void _LoadRom(string filename, string archive = null) - { - var args = new LoadRomArgs(); - args.OpenAdvanced = new OpenAdvanced_OpenRom { Path = filename }; - LoadRom(filename, args); - } - - private void _LoadState(string filename, string archive = null) - { - LoadState(filename, Path.GetFileName(filename)); - } - - private void _LoadWatch(string filename, string archive = null) - { - GlobalWin.Tools.LoadRamWatch(true); - (GlobalWin.Tools.Get() as RamWatch).LoadWatchFile(new FileInfo(filename), false); - } - - #endregion - - private void ProcessFileList(IEnumerable fileList, ref Dictionary> sortedFiles, string archive = null) - { - foreach (string file in fileList) - { - var ext = Path.GetExtension(file).ToUpper() ?? String.Empty; - FileInformation fileInformation = new FileInformation(Path.GetDirectoryName(file), Path.GetFileName(file), archive); - - switch (ext) - { - case ".LUA": - sortedFiles[LoadOrdering.LUASCRIPT].Add(fileInformation); - break; - case ".LUASES": - sortedFiles[LoadOrdering.LUASESSION].Add(fileInformation); - break; - case ".STATE": - sortedFiles[LoadOrdering.STATE].Add(fileInformation); - break; - case ".CHT": - sortedFiles[LoadOrdering.CHEAT].Add(fileInformation); - break; - case ".WCH": - sortedFiles[LoadOrdering.WATCH].Add(fileInformation); - break; - case ".CDL": - sortedFiles[LoadOrdering.CDLFILE].Add(fileInformation); - break; - default: - if (MovieService.IsValidMovieExtension(ext)) - sortedFiles[LoadOrdering.MOVIEFILE].Add(fileInformation); - else if (MovieImport.IsValidMovieExtension(ext)) - sortedFiles[LoadOrdering.LEGACYMOVIEFILE].Add(fileInformation); - else if (knownROMExtensions.Contains(ext)) - { - if (String.IsNullOrEmpty(archive) || !nonArchive.Contains(ext)) - sortedFiles[LoadOrdering.ROM].Add(fileInformation); - } - else - { - /* Because the existing behaviour for archives is to try loading - * ROMs out of them, that is exactly what we are going to continue - * to do at present. Ideally, the archive should be scanned and - * relevant files should be extracted, but see the note below for - * further details. - */ - int offset = 0; - bool executable = false; - var archiveHandler = new SevenZipSharpArchiveHandler(); - - if (String.IsNullOrEmpty(archive) && archiveHandler.CheckSignature(file, out offset, out executable)) - sortedFiles[LoadOrdering.ROM].Add(fileInformation); - - /* - * This is where handling archives would go. - * Right now, that's going to be a HUGE hassle, because of the problem with - * saving things into the archive (no) and with everything requiring filenames - * and not streams (also no), so for the purposes of making drag/drop more robust, - * I am not building this out just yet. - * -- Adam Michaud (Invariel) - - int offset = 0; - bool executable = false; - var archiveHandler = new SevenZipSharpArchiveHandler(); - - // Not going to process nested archives at the moment. - if (String.IsNullOrEmpty (archive) && archiveHandler.CheckSignature(file, out offset, out executable)) - { - List fileNames = new List(); - var openedArchive = archiveHandler.Construct (file); - - foreach (BizHawk.Common.HawkFileArchiveItem item in openedArchive.Scan ()) - fileNames.Add(item.Name); - - ProcessFileList(fileNames.ToArray(), ref sortedFiles, file); - - openedArchive.Dispose(); - } - archiveHandler.Dispose(); - */ - } - break; - } - } - } - - private void _FormDragDrop_internal(object sender, DragEventArgs e) - { - /* - * Refactor, moving the loading of particular files into separate functions that can - * then be used by this code, and loading individual files through the file dialogue. - * - * Step 1: - * Build a dictionary of relevant files from everything that was dragged and dropped. - * This includes peeking into all relevant archives and using their files. - * - * Step 2: - * Perhaps ask the user which of a particular file type they want to use. - * Example: rom1.nes, rom2.smc, rom3.cue are drag-dropped, ask the user which they want to use. - * - * Step 3: - * Load all of the relevant files, in priority order: - * 1) The ROM - * 2) State - * 3) Watch files - * 4) Code Data Logger (CDL) - * 5) LUA sessions - * 6) LUA scripts - * 7) Cheat files - * 8) Movie Playback Files - * - * Bonus: - * Make that order easy to change in the code, heavily suggesting ROM and playback as first and last respectively. - */ - - var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); - Dictionary> sortedFiles = new Dictionary>(); - - // Initialize the dictionary's lists. - foreach (LoadOrdering value in Enum.GetValues(typeof(LoadOrdering))) - { - sortedFiles.Add(value, new List()); - } - - ProcessFileList(HawkFile.Util_ResolveLinks(filePaths), ref sortedFiles, null); - - // For each of the different types of item, if there are no items of that type, skip them. - // If there is exactly one of that type of item, load it. - // If there is more than one, ask. - - foreach (LoadOrdering value in Enum.GetValues(typeof(LoadOrdering))) - { - switch (sortedFiles[value].Count) - { - case 0: - break; - case 1: - FileInformation fileInformation = sortedFiles[value].First(); - string filename = Path.Combine(new string[] { fileInformation.directoryName, fileInformation.fileName }); - - switch (value) - { - case LoadOrdering.ROM: - _LoadRom(filename, fileInformation.archiveName); - break; - case LoadOrdering.STATE: - _LoadState(filename, fileInformation.archiveName); - break; - case LoadOrdering.WATCH: - _LoadWatch(filename, fileInformation.archiveName); - break; - case LoadOrdering.CDLFILE: - _LoadCDL(filename, fileInformation.archiveName); - break; - case LoadOrdering.LUASESSION: - _LoadLuaSession(filename, fileInformation.archiveName); - break; - case LoadOrdering.LUASCRIPT: - _LoadLuaFile(filename, fileInformation.archiveName); - break; - case LoadOrdering.CHEAT: - _LoadCheats(filename, fileInformation.archiveName); - break; - case LoadOrdering.MOVIEFILE: - case LoadOrdering.LEGACYMOVIEFILE: - // I don't really like this hack, but for now, we only want to load one movie file. - if (sortedFiles[LoadOrdering.MOVIEFILE].Count + sortedFiles[LoadOrdering.LEGACYMOVIEFILE].Count > 1) - break; - - if (value == LoadOrdering.MOVIEFILE) - _LoadMovie(filename, fileInformation.archiveName); - else - _LoadLegacyMovie(filename, fileInformation.archiveName); - break; - } - break; - default: - break; - } - } - } - } -} +using BizHawk.Common; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; +using BizHawk.Emulation.Cores.Calculators; +using BizHawk.Emulation.Cores.ColecoVision; +using BizHawk.Emulation.Cores.Nintendo.Gameboy; +using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.N64; +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.Common; + +using BizHawk.Client.EmuHawk.CustomControls; +using BizHawk.Client.EmuHawk.WinFormExtensions; +using BizHawk.Client.EmuHawk.ToolExtensions; +using BizHawk.Emulation.Cores.Computers.AppleII; +using BizHawk.Client.ApiHawk; + +namespace BizHawk.Client.EmuHawk +{ + partial class MainForm + { + private enum LoadOrdering + { + ROM, + STATE, + WATCH, + CDLFILE, + LUASESSION, + LUASCRIPT, + CHEAT, + MOVIEFILE, + LEGACYMOVIEFILE + } + + public struct FileInformation + { + public string directoryName; + public string fileName; + public string archiveName; + + public FileInformation(string directory, string file, string archive) + { + directoryName = directory; + fileName = file; + archiveName = archive; + } + } + + // This is the list from MainForm->RomFilter()'s non-developer build. It needs to be kept up-to-date when new cores are added. + readonly string[] knownROMExtensions = { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF" }; + readonly string[] nonArchive = { ".ISO", ".CUE", ".CCD" }; + + #region Loaders + + // According to the documentation (http://tasvideos.org/Bizhawk/CodeDataLogger.html), + // Currently supported for: PCE, GB/GBC, SMS/GG, Genesis, SNES + // Perhaps the 'is PCEngine' requirement needs to be expanded. + private void _LoadCDL(string filename, string archive = null) + { + if (!(Global.Emulator is PCEngine)) + return; + + GlobalWin.Tools.Load(); + (GlobalWin.Tools.Get() as CDL).LoadFile(filename); + } + + private void _LoadCheats(string filename, string archive = null) + { + Global.CheatList.Load(filename, false); + GlobalWin.Tools.Load(); + } + + private void _LoadLegacyMovie(string filename, string archive = null) + { + if (Global.Emulator.IsNull()) + { + OpenRom(); + } + + if (Global.Emulator.IsNull()) + { + return; + } + + // tries to open a legacy movie format by importing it + string errorMsg; + string warningMsg; + var movie = MovieImport.ImportFile(filename, out errorMsg, out warningMsg); + if (!string.IsNullOrEmpty(errorMsg)) + { + MessageBox.Show(errorMsg, "Conversion error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + else + { + // fix movie extension to something palatable for these purposes. + // for instance, something which doesnt clobber movies you already may have had. + // i'm evenly torn between this, and a file in %TEMP%, but since we dont really have a way to clean up this tempfile, i choose this: + StartNewMovie(movie, false); + } + + GlobalWin.OSD.AddMessage(warningMsg); + } + + private void _LoadLuaFile(string filename, string archive = null) + { + OpenLuaConsole(); + if (GlobalWin.Tools.Has()) + { + GlobalWin.Tools.LuaConsole.LoadLuaFile(filename); + } + } + + private void _LoadLuaSession(string filename, string archive = null) + { + OpenLuaConsole(); + if (GlobalWin.Tools.Has()) + { + GlobalWin.Tools.LuaConsole.LoadLuaSession(filename); + } + } + + private void _LoadMovie(string filename, string archive = null) + { + if (Global.Emulator.IsNull()) + { + OpenRom(); + } + + if (Global.Emulator.IsNull()) + { + return; + } + + StartNewMovie(MovieService.Get(filename), false); + } + + private void _LoadRom(string filename, string archive = null) + { + var args = new LoadRomArgs(); + args.OpenAdvanced = new OpenAdvanced_OpenRom { Path = filename }; + LoadRom(filename, args); + } + + private void _LoadState(string filename, string archive = null) + { + LoadState(filename, Path.GetFileName(filename)); + } + + private void _LoadWatch(string filename, string archive = null) + { + GlobalWin.Tools.LoadRamWatch(true); + (GlobalWin.Tools.Get() as RamWatch).LoadWatchFile(new FileInfo(filename), false); + } + + #endregion + + private void ProcessFileList(IEnumerable fileList, ref Dictionary> sortedFiles, string archive = null) + { + foreach (string file in fileList) + { + var ext = Path.GetExtension(file).ToUpper() ?? String.Empty; + FileInformation fileInformation = new FileInformation(Path.GetDirectoryName(file), Path.GetFileName(file), archive); + + switch (ext) + { + case ".LUA": + sortedFiles[LoadOrdering.LUASCRIPT].Add(fileInformation); + break; + case ".LUASES": + sortedFiles[LoadOrdering.LUASESSION].Add(fileInformation); + break; + case ".STATE": + sortedFiles[LoadOrdering.STATE].Add(fileInformation); + break; + case ".CHT": + sortedFiles[LoadOrdering.CHEAT].Add(fileInformation); + break; + case ".WCH": + sortedFiles[LoadOrdering.WATCH].Add(fileInformation); + break; + case ".CDL": + sortedFiles[LoadOrdering.CDLFILE].Add(fileInformation); + break; + default: + if (MovieService.IsValidMovieExtension(ext)) + sortedFiles[LoadOrdering.MOVIEFILE].Add(fileInformation); + else if (MovieImport.IsValidMovieExtension(ext)) + sortedFiles[LoadOrdering.LEGACYMOVIEFILE].Add(fileInformation); + else if (knownROMExtensions.Contains(ext)) + { + if (String.IsNullOrEmpty(archive) || !nonArchive.Contains(ext)) + sortedFiles[LoadOrdering.ROM].Add(fileInformation); + } + else + { + /* Because the existing behaviour for archives is to try loading + * ROMs out of them, that is exactly what we are going to continue + * to do at present. Ideally, the archive should be scanned and + * relevant files should be extracted, but see the note below for + * further details. + */ + int offset = 0; + bool executable = false; + var archiveHandler = new SevenZipSharpArchiveHandler(); + + if (String.IsNullOrEmpty(archive) && archiveHandler.CheckSignature(file, out offset, out executable)) + sortedFiles[LoadOrdering.ROM].Add(fileInformation); + + /* + * This is where handling archives would go. + * Right now, that's going to be a HUGE hassle, because of the problem with + * saving things into the archive (no) and with everything requiring filenames + * and not streams (also no), so for the purposes of making drag/drop more robust, + * I am not building this out just yet. + * -- Adam Michaud (Invariel) + + int offset = 0; + bool executable = false; + var archiveHandler = new SevenZipSharpArchiveHandler(); + + // Not going to process nested archives at the moment. + if (String.IsNullOrEmpty (archive) && archiveHandler.CheckSignature(file, out offset, out executable)) + { + List fileNames = new List(); + var openedArchive = archiveHandler.Construct (file); + + foreach (BizHawk.Common.HawkFileArchiveItem item in openedArchive.Scan ()) + fileNames.Add(item.Name); + + ProcessFileList(fileNames.ToArray(), ref sortedFiles, file); + + openedArchive.Dispose(); + } + archiveHandler.Dispose(); + */ + } + break; + } + } + } + + private void _FormDragDrop_internal(object sender, DragEventArgs e) + { + /* + * Refactor, moving the loading of particular files into separate functions that can + * then be used by this code, and loading individual files through the file dialogue. + * + * Step 1: + * Build a dictionary of relevant files from everything that was dragged and dropped. + * This includes peeking into all relevant archives and using their files. + * + * Step 2: + * Perhaps ask the user which of a particular file type they want to use. + * Example: rom1.nes, rom2.smc, rom3.cue are drag-dropped, ask the user which they want to use. + * + * Step 3: + * Load all of the relevant files, in priority order: + * 1) The ROM + * 2) State + * 3) Watch files + * 4) Code Data Logger (CDL) + * 5) LUA sessions + * 6) LUA scripts + * 7) Cheat files + * 8) Movie Playback Files + * + * Bonus: + * Make that order easy to change in the code, heavily suggesting ROM and playback as first and last respectively. + */ + + var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); + Dictionary> sortedFiles = new Dictionary>(); + + // Initialize the dictionary's lists. + foreach (LoadOrdering value in Enum.GetValues(typeof(LoadOrdering))) + { + sortedFiles.Add(value, new List()); + } + + ProcessFileList(HawkFile.Util_ResolveLinks(filePaths), ref sortedFiles, null); + + // For each of the different types of item, if there are no items of that type, skip them. + // If there is exactly one of that type of item, load it. + // If there is more than one, ask. + + foreach (LoadOrdering value in Enum.GetValues(typeof(LoadOrdering))) + { + switch (sortedFiles[value].Count) + { + case 0: + break; + case 1: + FileInformation fileInformation = sortedFiles[value].First(); + string filename = Path.Combine(new string[] { fileInformation.directoryName, fileInformation.fileName }); + + switch (value) + { + case LoadOrdering.ROM: + _LoadRom(filename, fileInformation.archiveName); + break; + case LoadOrdering.STATE: + _LoadState(filename, fileInformation.archiveName); + break; + case LoadOrdering.WATCH: + _LoadWatch(filename, fileInformation.archiveName); + break; + case LoadOrdering.CDLFILE: + _LoadCDL(filename, fileInformation.archiveName); + break; + case LoadOrdering.LUASESSION: + _LoadLuaSession(filename, fileInformation.archiveName); + break; + case LoadOrdering.LUASCRIPT: + _LoadLuaFile(filename, fileInformation.archiveName); + break; + case LoadOrdering.CHEAT: + _LoadCheats(filename, fileInformation.archiveName); + break; + case LoadOrdering.MOVIEFILE: + case LoadOrdering.LEGACYMOVIEFILE: + // I don't really like this hack, but for now, we only want to load one movie file. + if (sortedFiles[LoadOrdering.MOVIEFILE].Count + sortedFiles[LoadOrdering.LEGACYMOVIEFILE].Count > 1) + break; + + if (value == LoadOrdering.MOVIEFILE) + _LoadMovie(filename, fileInformation.archiveName); + else + _LoadLegacyMovie(filename, fileInformation.archiveName); + break; + } + break; + default: + break; + } + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/GLManager.cs b/BizHawk.Client.EmuHawk/GLManager.cs index f30a0dc8d3..6ea3476a18 100644 --- a/BizHawk.Client.EmuHawk/GLManager.cs +++ b/BizHawk.Client.EmuHawk/GLManager.cs @@ -1,32 +1,32 @@ -using System; -using BizHawk.Bizware.BizwareGL; - - -namespace BizHawk.Client.EmuHawk -{ - /// - /// This singleton class manages OpenGL contexts, in an effort to minimize context changes. - /// - public class GLManager : IDisposable - { - private GLManager() - { - - } - - public void Dispose() - { - } - +using System; +using BizHawk.Bizware.BizwareGL; + + +namespace BizHawk.Client.EmuHawk +{ + /// + /// This singleton class manages OpenGL contexts, in an effort to minimize context changes. + /// + public class GLManager : IDisposable + { + private GLManager() + { + + } + + public void Dispose() + { + } + public static GLManager Instance { get; private set; } - Bizware.BizwareGL.Drivers.OpenTK.IGL_TK MainContext; - - public static void CreateInstance(Bizware.BizwareGL.Drivers.OpenTK.IGL_TK mainContext) - { - if (Instance != null) throw new InvalidOperationException("Attempt to create more than one GLManager"); + Bizware.BizwareGL.Drivers.OpenTK.IGL_TK MainContext; + + public static void CreateInstance(Bizware.BizwareGL.Drivers.OpenTK.IGL_TK mainContext) + { + if (Instance != null) throw new InvalidOperationException("Attempt to create more than one GLManager"); Instance = new GLManager(); - Instance.MainContext = mainContext; + Instance.MainContext = mainContext; } public void ReleaseGLContext(object o) @@ -38,77 +38,77 @@ namespace BizHawk.Client.EmuHawk //[System.Runtime.InteropServices.DllImport("opengl32.dll")] //bool wglShareLists(IntPtr hglrc1, IntPtr hglrc2); - public ContextRef CreateGLContext(int major_version, int minor_version, bool forward_compatible) + public ContextRef CreateGLContext(int major_version, int minor_version, bool forward_compatible) { - var gl = new Bizware.BizwareGL.Drivers.OpenTK.IGL_TK(major_version, minor_version, forward_compatible); - var ret = new ContextRef { gl = gl }; - return ret; - } - - public ContextRef GetContextForGraphicsControl(GraphicsControl gc) - { - return new ContextRef - { - gc = gc, - gl = gc.IGL - }; - } - - /// - /// This might not be a GL implementation. If it isnt GL, then setting it as active context is just NOP - /// - public ContextRef GetContextForIGL(IGL gl) - { - return new ContextRef - { - gl = gl - }; - } - - ContextRef ActiveContext; - - public void Invalidate() - { - ActiveContext = null; - } - - public void Activate(ContextRef cr) - { - bool begun = false; - - //this needs a begin signal to set the swap chain to the next backbuffer - if (cr.gl is BizHawk.Bizware.BizwareGL.Drivers.SlimDX.IGL_SlimDX9) - { - cr.gc.Begin(); - begun = true; - } - - if (cr == ActiveContext) - return; - - ActiveContext = cr; - if (cr.gc != null) - { - //TODO - this is checking the current context inside to avoid an extra NOP context change. make this optional or remove it, since we're tracking it here - if(!begun) - cr.gc.Begin(); - } - else if (cr.gl != null) - { - if(cr.gl is BizHawk.Bizware.BizwareGL.Drivers.OpenTK.IGL_TK) - ((BizHawk.Bizware.BizwareGL.Drivers.OpenTK.IGL_TK)cr.gl).MakeDefaultCurrent(); - } - } - - public void Deactivate() - { - //this is here for future use and tracking purposes.. however.. instead of relying on this, we should just make sure we always activate what we need before we use it - } - - public class ContextRef - { - public IGL gl; - public GraphicsControl gc; - } - } + var gl = new Bizware.BizwareGL.Drivers.OpenTK.IGL_TK(major_version, minor_version, forward_compatible); + var ret = new ContextRef { gl = gl }; + return ret; + } + + public ContextRef GetContextForGraphicsControl(GraphicsControl gc) + { + return new ContextRef + { + gc = gc, + gl = gc.IGL + }; + } + + /// + /// This might not be a GL implementation. If it isnt GL, then setting it as active context is just NOP + /// + public ContextRef GetContextForIGL(IGL gl) + { + return new ContextRef + { + gl = gl + }; + } + + ContextRef ActiveContext; + + public void Invalidate() + { + ActiveContext = null; + } + + public void Activate(ContextRef cr) + { + bool begun = false; + + //this needs a begin signal to set the swap chain to the next backbuffer + if (cr.gl is BizHawk.Bizware.BizwareGL.Drivers.SlimDX.IGL_SlimDX9) + { + cr.gc.Begin(); + begun = true; + } + + if (cr == ActiveContext) + return; + + ActiveContext = cr; + if (cr.gc != null) + { + //TODO - this is checking the current context inside to avoid an extra NOP context change. make this optional or remove it, since we're tracking it here + if(!begun) + cr.gc.Begin(); + } + else if (cr.gl != null) + { + if(cr.gl is BizHawk.Bizware.BizwareGL.Drivers.OpenTK.IGL_TK) + ((BizHawk.Bizware.BizwareGL.Drivers.OpenTK.IGL_TK)cr.gl).MakeDefaultCurrent(); + } + } + + public void Deactivate() + { + //this is here for future use and tracking purposes.. however.. instead of relying on this, we should just make sure we always activate what we need before we use it + } + + public class ContextRef + { + public IGL gl; + public GraphicsControl gc; + } + } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/PSX/PSXControllerConfigNew.cs b/BizHawk.Client.EmuHawk/config/PSX/PSXControllerConfigNew.cs index a51978ed68..c49f1efabf 100644 --- a/BizHawk.Client.EmuHawk/config/PSX/PSXControllerConfigNew.cs +++ b/BizHawk.Client.EmuHawk/config/PSX/PSXControllerConfigNew.cs @@ -1,43 +1,43 @@ -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.Common; -using BizHawk.Emulation.Cores.Sony.PSX; -using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk.WinFormExtensions; -using BizHawk.Common.ReflectionExtensions; - -namespace BizHawk.Client.EmuHawk -{ - public partial class PSXControllerConfigNew : Form - { - public PSXControllerConfigNew() - { - InitializeComponent(); - } - - private void PSXControllerConfigNew_Load(object sender, EventArgs e) - { - //populate combo boxes - foreach(var combo in new[]{combo_1_1,combo_1_2,combo_1_3,combo_1_4,combo_2_1,combo_2_2,combo_2_3,combo_2_4}) - { - combo.Items.Add("-Nothing-"); - combo.Items.Add("Gamepad"); - combo.Items.Add("Dual Shock"); - combo.Items.Add("Dual Analog"); - combo.SelectedIndex = 0; - } - +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.Common; +using BizHawk.Emulation.Cores.Sony.PSX; +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.WinFormExtensions; +using BizHawk.Common.ReflectionExtensions; + +namespace BizHawk.Client.EmuHawk +{ + public partial class PSXControllerConfigNew : Form + { + public PSXControllerConfigNew() + { + InitializeComponent(); + } + + private void PSXControllerConfigNew_Load(object sender, EventArgs e) + { + //populate combo boxes + foreach(var combo in new[]{combo_1_1,combo_1_2,combo_1_3,combo_1_4,combo_2_1,combo_2_2,combo_2_3,combo_2_4}) + { + combo.Items.Add("-Nothing-"); + combo.Items.Add("Gamepad"); + combo.Items.Add("Dual Shock"); + combo.Items.Add("Dual Analog"); + combo.SelectedIndex = 0; + } + var psxSettings = ((Octoshock)Global.Emulator).GetSyncSettings(); - GuiFromUserConfig(psxSettings.FIOConfig); - - RefreshLabels(); + GuiFromUserConfig(psxSettings.FIOConfig); + + RefreshLabels(); } void GuiFromUserConfig(OctoshockFIOConfigUser user) @@ -56,7 +56,7 @@ namespace BizHawk.Client.EmuHawk if (user.Devices8[i] == OctoshockDll.ePeripheralType.DualShock) combo.SelectedIndex = 2; if (user.Devices8[i] == OctoshockDll.ePeripheralType.DualAnalog) combo.SelectedIndex = 3; } - } + } OctoshockFIOConfigUser UserConfigFromGui() { @@ -79,60 +79,60 @@ namespace BizHawk.Client.EmuHawk } return uc; - } - - void RefreshLabels() + } + + void RefreshLabels() { - var uc = UserConfigFromGui(); - - bool b1 = uc.Multitaps[0]; - lbl_1_1.Visible = b1; - lbl_1_2.Visible = b1; - lbl_1_3.Visible = b1; - lbl_1_4.Visible = b1; - combo_1_2.Enabled = b1; - combo_1_3.Enabled = b1; - combo_1_4.Enabled = b1; - lbl_p_1_2.Visible = b1; - lbl_p_1_3.Visible = b1; + var uc = UserConfigFromGui(); + + bool b1 = uc.Multitaps[0]; + lbl_1_1.Visible = b1; + lbl_1_2.Visible = b1; + lbl_1_3.Visible = b1; + lbl_1_4.Visible = b1; + combo_1_2.Enabled = b1; + combo_1_3.Enabled = b1; + combo_1_4.Enabled = b1; + lbl_p_1_2.Visible = b1; + lbl_p_1_3.Visible = b1; lbl_p_1_4.Visible = b1; - bool b2 = uc.Multitaps[1]; - lbl_2_1.Visible = b2; - lbl_2_2.Visible = b2; - lbl_2_3.Visible = b2; - lbl_2_4.Visible = b2; - combo_2_2.Enabled = b2; - combo_2_3.Enabled = b2; - combo_2_4.Enabled = b2; - lbl_p_2_2.Visible = b2; - lbl_p_2_3.Visible = b2; + bool b2 = uc.Multitaps[1]; + lbl_2_1.Visible = b2; + lbl_2_2.Visible = b2; + lbl_2_3.Visible = b2; + lbl_2_4.Visible = b2; + combo_2_2.Enabled = b2; + combo_2_3.Enabled = b2; + combo_2_4.Enabled = b2; + lbl_p_2_2.Visible = b2; + lbl_p_2_3.Visible = b2; lbl_p_2_4.Visible = b2; - var LC = uc.ToLogical(); - - var p_labels = new[] { lbl_p_1_1,lbl_p_1_2,lbl_p_1_3,lbl_p_1_4,lbl_p_2_1,lbl_p_2_2,lbl_p_2_3,lbl_p_2_4}; - for (int i = 0; i < 8; i++) - { - var lbl = p_labels[i]; - if (LC.PlayerAssignments[i] == -1) - lbl.Visible = false; - else - { - lbl.Text = "P" + LC.PlayerAssignments[i]; - lbl.Visible = true; - } - } - } - - private void cb_changed(object sender, EventArgs e) - { - RefreshLabels(); - } - - private void combo_SelectedIndexChanged(object sender, EventArgs e) - { - RefreshLabels(); + var LC = uc.ToLogical(); + + var p_labels = new[] { lbl_p_1_1,lbl_p_1_2,lbl_p_1_3,lbl_p_1_4,lbl_p_2_1,lbl_p_2_2,lbl_p_2_3,lbl_p_2_4}; + for (int i = 0; i < 8; i++) + { + var lbl = p_labels[i]; + if (LC.PlayerAssignments[i] == -1) + lbl.Visible = false; + else + { + lbl.Text = "P" + LC.PlayerAssignments[i]; + lbl.Visible = true; + } + } + } + + private void cb_changed(object sender, EventArgs e) + { + RefreshLabels(); + } + + private void combo_SelectedIndexChanged(object sender, EventArgs e) + { + RefreshLabels(); } private void btnOK_Click(object sender, EventArgs e) @@ -145,6 +145,6 @@ namespace BizHawk.Client.EmuHawk DialogResult = DialogResult.OK; Close(); - } - } -} + } + } +} diff --git a/BizHawk.Client.EmuHawk/tools/CDL.cs b/BizHawk.Client.EmuHawk/tools/CDL.cs index 105292189f..a2308fb7cc 100644 --- a/BizHawk.Client.EmuHawk/tools/CDL.cs +++ b/BizHawk.Client.EmuHawk/tools/CDL.cs @@ -1,188 +1,188 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Windows.Forms; - -using BizHawk.Emulation.Common; - -using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk.ToolExtensions; - -//TODO - select which memorydomains go out to the CDL file. will this cause a problem when re-importing it? - //perhaps missing domains shouldnt fail a check -//OR - just add a contextmenu option to the listview item that selects it for export. -//TODO - add a contextmenu option which warps to the hexeditor with the provided domain selected for visualizing on the hex editor. -//TODO - consider setting colors for columns in CDL -//TODO - option to print domain name in caption instead of 0x01 etc. -//TODO - context menu should have copy option too - -namespace BizHawk.Client.EmuHawk -{ - public partial class CDL : ToolFormBase, IToolFormAutoConfig - { - private RecentFiles _recent_fld = new RecentFiles(); - - [ConfigPersist] - private RecentFiles _recent - { - get - { return _recent_fld; } - set - { - _recent_fld = value; - if (_recent_fld.AutoLoad) - { - LoadFile(_recent.MostRecent); - SetCurrentFilename(_recent.MostRecent); - } - } - } - - void SetCurrentFilename(string fname) - { - _currentFilename = fname; - if (_currentFilename == null) - Text = "Code Data Logger"; - else Text = string.Format("Code Data Logger - {0}", fname); - } - - [RequiredService] - private IMemoryDomains MemoryDomains { get; set; } - - [RequiredService] - private ICodeDataLogger CodeDataLogger { get; set; } - - private string _currentFilename = null; - private CodeDataLog _cdl; - - public CDL() - { - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - SetStyle(ControlStyles.UserPaint, true); - SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - InitializeComponent(); - - tsbViewStyle.SelectedIndex = 0; +using System; +using System.Collections.Generic; +using System.IO; +using System.Windows.Forms; + +using BizHawk.Emulation.Common; + +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.ToolExtensions; + +//TODO - select which memorydomains go out to the CDL file. will this cause a problem when re-importing it? + //perhaps missing domains shouldnt fail a check +//OR - just add a contextmenu option to the listview item that selects it for export. +//TODO - add a contextmenu option which warps to the hexeditor with the provided domain selected for visualizing on the hex editor. +//TODO - consider setting colors for columns in CDL +//TODO - option to print domain name in caption instead of 0x01 etc. +//TODO - context menu should have copy option too + +namespace BizHawk.Client.EmuHawk +{ + public partial class CDL : ToolFormBase, IToolFormAutoConfig + { + private RecentFiles _recent_fld = new RecentFiles(); + + [ConfigPersist] + private RecentFiles _recent + { + get + { return _recent_fld; } + set + { + _recent_fld = value; + if (_recent_fld.AutoLoad) + { + LoadFile(_recent.MostRecent); + SetCurrentFilename(_recent.MostRecent); + } + } } - public void NewUpdate(ToolFormUpdateType type) { } - - public void UpdateValues() - { - UpdateDisplay(false); - } - - public void FastUpdate() - { - // Do nothing - } - - public void Restart() - { - //don't try to recover the current CDL! - //even though it seems like it might be nice, it might get mixed up between games. even if we use CheckCDL. Switching games with the same memory map will be bad. - _cdl = null; - SetCurrentFilename(null); - SetLoggingActiveCheck(false); - UpdateDisplay(true); - } - - void SetLoggingActiveCheck(bool value) - { - tsbLoggingActive.Checked = value; - } - - string[][] listContents = new string[0][]; - - private void UpdateDisplay(bool force) - { - if (!tsbViewUpdate.Checked && !force) - return; - - - if (_cdl == null) - { - lvCDL.BeginUpdate(); - lvCDL.Items.Clear(); - lvCDL.EndUpdate(); - return; - } - - lvCDL.BeginUpdate(); - - listContents = new string[_cdl.Count][]; - - int idx = 0; - foreach (var kvp in _cdl) - { - int[] totals = new int[8]; - int total = 0; - unsafe - { - int* map = stackalloc int[256]; - for (int i = 0; i < 256; i++) - map[i] = 0; - - fixed (byte* data = kvp.Value) - { - byte* src = data; - byte* end = data + kvp.Value.Length; - while (src < end) - { - byte s = *src++; - map[s]++; - } - } - - for (int i = 0; i < 256; i++) - { - if(i!=0) total += map[i]; - if ((i & 0x01) != 0) totals[0] += map[i]; - if ((i & 0x02) != 0) totals[1] += map[i]; - if ((i & 0x04) != 0) totals[2] += map[i]; - if ((i & 0x08) != 0) totals[3] += map[i]; - if ((i & 0x10) != 0) totals[4] += map[i]; - if ((i & 0x20) != 0) totals[5] += map[i]; - if ((i & 0x40) != 0) totals[6] += map[i]; - if ((i & 0x80) != 0) totals[7] += map[i]; - } - } - - var bm = _cdl.GetBlockMap(); - long addr = bm[kvp.Key]; - - var lvi = listContents[idx++] = new string[13]; - lvi[0] = string.Format("{0:X8}", addr); - lvi[1] = kvp.Key; - lvi[2] = string.Format("{0:0.00}%", total / (float)kvp.Value.Length * 100f); - if (tsbViewStyle.SelectedIndex == 2) - lvi[3] = string.Format("{0:0.00}", total / 1024.0f); - else - lvi[3] = string.Format("{0}", total); - if (tsbViewStyle.SelectedIndex == 2) - { - int n = (int)(kvp.Value.Length / 1024.0f); - float ncheck = kvp.Value.Length / 1024.0f; - lvi[4] = string.Format("of {0}{1} KBytes", n == ncheck ? "" : "~", n); - } - else - lvi[4] = string.Format("of {0} Bytes", kvp.Value.Length); - for (int i = 0; i < 8; i++) - { - if (tsbViewStyle.SelectedIndex == 0) - lvi[5 + i] = string.Format("{0:0.00}%", totals[i] / (float)kvp.Value.Length * 100f); - if (tsbViewStyle.SelectedIndex == 1) - lvi[5 + i] = string.Format("{0}", totals[i]); - if (tsbViewStyle.SelectedIndex == 2) - lvi[5 + i] = string.Format("{0:0.00}", totals[i] / 1024.0f); - } - - } - lvCDL.VirtualListSize = _cdl.Count; - lvCDL.EndUpdate(); - } - - public bool AskSaveChanges() + void SetCurrentFilename(string fname) + { + _currentFilename = fname; + if (_currentFilename == null) + Text = "Code Data Logger"; + else Text = string.Format("Code Data Logger - {0}", fname); + } + + [RequiredService] + private IMemoryDomains MemoryDomains { get; set; } + + [RequiredService] + private ICodeDataLogger CodeDataLogger { get; set; } + + private string _currentFilename = null; + private CodeDataLog _cdl; + + public CDL() + { + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.UserPaint, true); + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + InitializeComponent(); + + tsbViewStyle.SelectedIndex = 0; + } + + public void NewUpdate(ToolFormUpdateType type) { } + + public void UpdateValues() + { + UpdateDisplay(false); + } + + public void FastUpdate() + { + // Do nothing + } + + public void Restart() + { + //don't try to recover the current CDL! + //even though it seems like it might be nice, it might get mixed up between games. even if we use CheckCDL. Switching games with the same memory map will be bad. + _cdl = null; + SetCurrentFilename(null); + SetLoggingActiveCheck(false); + UpdateDisplay(true); + } + + void SetLoggingActiveCheck(bool value) + { + tsbLoggingActive.Checked = value; + } + + string[][] listContents = new string[0][]; + + private void UpdateDisplay(bool force) + { + if (!tsbViewUpdate.Checked && !force) + return; + + + if (_cdl == null) + { + lvCDL.BeginUpdate(); + lvCDL.Items.Clear(); + lvCDL.EndUpdate(); + return; + } + + lvCDL.BeginUpdate(); + + listContents = new string[_cdl.Count][]; + + int idx = 0; + foreach (var kvp in _cdl) + { + int[] totals = new int[8]; + int total = 0; + unsafe + { + int* map = stackalloc int[256]; + for (int i = 0; i < 256; i++) + map[i] = 0; + + fixed (byte* data = kvp.Value) + { + byte* src = data; + byte* end = data + kvp.Value.Length; + while (src < end) + { + byte s = *src++; + map[s]++; + } + } + + for (int i = 0; i < 256; i++) + { + if(i!=0) total += map[i]; + if ((i & 0x01) != 0) totals[0] += map[i]; + if ((i & 0x02) != 0) totals[1] += map[i]; + if ((i & 0x04) != 0) totals[2] += map[i]; + if ((i & 0x08) != 0) totals[3] += map[i]; + if ((i & 0x10) != 0) totals[4] += map[i]; + if ((i & 0x20) != 0) totals[5] += map[i]; + if ((i & 0x40) != 0) totals[6] += map[i]; + if ((i & 0x80) != 0) totals[7] += map[i]; + } + } + + var bm = _cdl.GetBlockMap(); + long addr = bm[kvp.Key]; + + var lvi = listContents[idx++] = new string[13]; + lvi[0] = string.Format("{0:X8}", addr); + lvi[1] = kvp.Key; + lvi[2] = string.Format("{0:0.00}%", total / (float)kvp.Value.Length * 100f); + if (tsbViewStyle.SelectedIndex == 2) + lvi[3] = string.Format("{0:0.00}", total / 1024.0f); + else + lvi[3] = string.Format("{0}", total); + if (tsbViewStyle.SelectedIndex == 2) + { + int n = (int)(kvp.Value.Length / 1024.0f); + float ncheck = kvp.Value.Length / 1024.0f; + lvi[4] = string.Format("of {0}{1} KBytes", n == ncheck ? "" : "~", n); + } + else + lvi[4] = string.Format("of {0} Bytes", kvp.Value.Length); + for (int i = 0; i < 8; i++) + { + if (tsbViewStyle.SelectedIndex == 0) + lvi[5 + i] = string.Format("{0:0.00}%", totals[i] / (float)kvp.Value.Length * 100f); + if (tsbViewStyle.SelectedIndex == 1) + lvi[5 + i] = string.Format("{0}", totals[i]); + if (tsbViewStyle.SelectedIndex == 2) + lvi[5 + i] = string.Format("{0:0.00}", totals[i] / 1024.0f); + } + + } + lvCDL.VirtualListSize = _cdl.Count; + lvCDL.EndUpdate(); + } + + public bool AskSaveChanges() { //nothing to fear: if (_cdl == null) @@ -208,108 +208,108 @@ namespace BizHawk.Client.EmuHawk } } - return true; - } - - public bool UpdateBefore - { - get { return false; } - } - - public void LoadFile(string path) - { - using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) - { - var newCDL = new CodeDataLog(); - newCDL.Load(fs); - - //have the core create a CodeDataLog to check mapping information against - var testCDL = new CodeDataLog(); - CodeDataLogger.NewCDL(testCDL); - if (!newCDL.Check(testCDL)) - { - MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); - return; - } - - //ok, it's all good: - _cdl = newCDL; + return true; + } + + public bool UpdateBefore + { + get { return false; } + } + + public void LoadFile(string path) + { + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + var newCDL = new CodeDataLog(); + newCDL.Load(fs); + + //have the core create a CodeDataLog to check mapping information against + var testCDL = new CodeDataLog(); + CodeDataLogger.NewCDL(testCDL); + if (!newCDL.Check(testCDL)) + { + MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); + return; + } + + //ok, it's all good: + _cdl = newCDL; CodeDataLogger.SetCDL(null); - if (tsbLoggingActive.Checked || Global.Config.CDLAutoStart) - CodeDataLogger.SetCDL(_cdl); - - SetCurrentFilename(path); - } - - UpdateDisplay(true); - } - - private void FileSubMenu_DropDownOpened(object sender, EventArgs e) - { - SaveMenuItem.Enabled = _currentFilename != null; - SaveAsMenuItem.Enabled = - AppendMenuItem.Enabled = - ClearMenuItem.Enabled = - DisassembleMenuItem.Enabled = + if (tsbLoggingActive.Checked || Global.Config.CDLAutoStart) + CodeDataLogger.SetCDL(_cdl); + + SetCurrentFilename(path); + } + + UpdateDisplay(true); + } + + private void FileSubMenu_DropDownOpened(object sender, EventArgs e) + { + SaveMenuItem.Enabled = _currentFilename != null; + SaveAsMenuItem.Enabled = + AppendMenuItem.Enabled = + ClearMenuItem.Enabled = + DisassembleMenuItem.Enabled = _cdl != null; miAutoSave.Checked = Global.Config.CDLAutoSave; - miAutoStart.Checked = Global.Config.CDLAutoStart; - } - - private void RecentSubMenu_DropDownOpened(object sender, EventArgs e) - { - RecentSubMenu.DropDownItems.Clear(); - RecentSubMenu.DropDownItems.AddRange(_recent.RecentMenu(LoadFile, true)); + miAutoStart.Checked = Global.Config.CDLAutoStart; } - void NewFileLogic() - { - _cdl = new CodeDataLog(); - CodeDataLogger.NewCDL(_cdl); - - if (tsbLoggingActive.Checked || Global.Config.CDLAutoStart) - CodeDataLogger.SetCDL(_cdl); - else CodeDataLogger.SetCDL(null); - - SetCurrentFilename(null); - - UpdateDisplay(true); - } - - private void NewMenuItem_Click(object sender, EventArgs e) - { - //take care not to clobber an existing CDL - if (_cdl != null) - { - var result = MessageBox.Show(this, "OK to create new CDL?", "Query", MessageBoxButtons.YesNo); - if (result != DialogResult.Yes) - return; - } - - NewFileLogic(); - } - - private void OpenMenuItem_Click(object sender, EventArgs e) - { - var file = OpenFileDialog( - _currentFilename, - PathManager.MakeAbsolutePath(Global.Config.PathEntries.LogPathFragment, null), - "Code Data Logger Files", - "cdl"); - - if (file == null) - return; - - //take care not to clobber an existing CDL - if (_cdl != null) - { - var result = MessageBox.Show(this, "OK to load new CDL?", "Query", MessageBoxButtons.YesNo); - if (result != DialogResult.Yes) - return; - } - - LoadFile(file.FullName); + private void RecentSubMenu_DropDownOpened(object sender, EventArgs e) + { + RecentSubMenu.DropDownItems.Clear(); + RecentSubMenu.DropDownItems.AddRange(_recent.RecentMenu(LoadFile, true)); + } + + void NewFileLogic() + { + _cdl = new CodeDataLog(); + CodeDataLogger.NewCDL(_cdl); + + if (tsbLoggingActive.Checked || Global.Config.CDLAutoStart) + CodeDataLogger.SetCDL(_cdl); + else CodeDataLogger.SetCDL(null); + + SetCurrentFilename(null); + + UpdateDisplay(true); + } + + private void NewMenuItem_Click(object sender, EventArgs e) + { + //take care not to clobber an existing CDL + if (_cdl != null) + { + var result = MessageBox.Show(this, "OK to create new CDL?", "Query", MessageBoxButtons.YesNo); + if (result != DialogResult.Yes) + return; + } + + NewFileLogic(); + } + + private void OpenMenuItem_Click(object sender, EventArgs e) + { + var file = OpenFileDialog( + _currentFilename, + PathManager.MakeAbsolutePath(Global.Config.PathEntries.LogPathFragment, null), + "Code Data Logger Files", + "cdl"); + + if (file == null) + return; + + //take care not to clobber an existing CDL + if (_cdl != null) + { + var result = MessageBox.Show(this, "OK to load new CDL?", "Query", MessageBoxButtons.YesNo); + if (result != DialogResult.Yes) + return; + } + + LoadFile(file.FullName); } void RunSave() @@ -319,120 +319,120 @@ namespace BizHawk.Client.EmuHawk { _cdl.Save(fs); } - } - - private void SaveMenuItem_Click(object sender, EventArgs e) + } + + private void SaveMenuItem_Click(object sender, EventArgs e) { if (_cdl == null) { MessageBox.Show(this, "Cannot save with no CDL loaded!", "Alert"); return; - } - - if (string.IsNullOrWhiteSpace(_currentFilename)) - { - RunSaveAs(); - return; } - RunSave(); - } - + if (string.IsNullOrWhiteSpace(_currentFilename)) + { + RunSaveAs(); + return; + } + + RunSave(); + } + /// /// returns false if the operation was canceled /// - bool RunSaveAs() - { - var file = SaveFileDialog( - _currentFilename, - PathManager.MakeAbsolutePath(Global.Config.PathEntries.LogPathFragment, null), - "Code Data Logger Files", + bool RunSaveAs() + { + var file = SaveFileDialog( + _currentFilename, + PathManager.MakeAbsolutePath(Global.Config.PathEntries.LogPathFragment, null), + "Code Data Logger Files", "cdl"); if (file == null) - return false; + return false; SetCurrentFilename(file.FullName); - RunSave(); - return true; - } - - private void SaveAsMenuItem_Click(object sender, EventArgs e) - { - RunSaveAs(); - } - - private void AppendMenuItem_Click(object sender, EventArgs e) - { - if (_cdl == null) - { - MessageBox.Show(this, "Cannot append with no CDL loaded!", "Alert"); - } - else - { - var file = ToolFormBase.OpenFileDialog( - _currentFilename, - PathManager.MakeAbsolutePath(Global.Config.PathEntries.LogPathFragment, null), - "Code Data Logger Files", - "cdl"); - - if (file != null) - { - using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read)) - { - var newCDL = new CodeDataLog(); - newCDL.Load(fs); - if (!_cdl.Check(newCDL)) - { - MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); - return; - } - _cdl.LogicalOrFrom(newCDL); - UpdateDisplay(true); - } - } - } - } - - private void ClearMenuItem_Click(object sender, EventArgs e) - { - if (_cdl == null) - { - MessageBox.Show(this, "Cannot clear with no CDL loaded!", "Alert"); - } - else - { - var result = MessageBox.Show(this, "OK to clear CDL?", "Query", MessageBoxButtons.YesNo); - if (result == DialogResult.Yes) - { - _cdl.ClearData(); - UpdateDisplay(true); - } - } - } - - private void DisassembleMenuItem_Click(object sender, EventArgs e) - { - if (_cdl == null) - { - MessageBox.Show(this, "Cannot disassemble with no CDL loaded!", "Alert"); - return; - } - - var sfd = new SaveFileDialog(); - var result = sfd.ShowDialog(this); - if (result == DialogResult.OK) - { - using (var fs = new FileStream(sfd.FileName, FileMode.Create, FileAccess.Write)) - { - CodeDataLogger.DisassembleCDL(fs, _cdl); - } - } - } - - private void ExitMenuItem_Click(object sender, EventArgs e) - { - Close(); + RunSave(); + return true; + } + + private void SaveAsMenuItem_Click(object sender, EventArgs e) + { + RunSaveAs(); + } + + private void AppendMenuItem_Click(object sender, EventArgs e) + { + if (_cdl == null) + { + MessageBox.Show(this, "Cannot append with no CDL loaded!", "Alert"); + } + else + { + var file = ToolFormBase.OpenFileDialog( + _currentFilename, + PathManager.MakeAbsolutePath(Global.Config.PathEntries.LogPathFragment, null), + "Code Data Logger Files", + "cdl"); + + if (file != null) + { + using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read)) + { + var newCDL = new CodeDataLog(); + newCDL.Load(fs); + if (!_cdl.Check(newCDL)) + { + MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); + return; + } + _cdl.LogicalOrFrom(newCDL); + UpdateDisplay(true); + } + } + } + } + + private void ClearMenuItem_Click(object sender, EventArgs e) + { + if (_cdl == null) + { + MessageBox.Show(this, "Cannot clear with no CDL loaded!", "Alert"); + } + else + { + var result = MessageBox.Show(this, "OK to clear CDL?", "Query", MessageBoxButtons.YesNo); + if (result == DialogResult.Yes) + { + _cdl.ClearData(); + UpdateDisplay(true); + } + } + } + + private void DisassembleMenuItem_Click(object sender, EventArgs e) + { + if (_cdl == null) + { + MessageBox.Show(this, "Cannot disassemble with no CDL loaded!", "Alert"); + return; + } + + var sfd = new SaveFileDialog(); + var result = sfd.ShowDialog(this); + if (result == DialogResult.OK) + { + using (var fs = new FileStream(sfd.FileName, FileMode.Create, FileAccess.Write)) + { + CodeDataLogger.DisassembleCDL(fs, _cdl); + } + } + } + + private void ExitMenuItem_Click(object sender, EventArgs e) + { + Close(); } protected override void OnClosing(System.ComponentModel.CancelEventArgs e) @@ -447,69 +447,69 @@ namespace BizHawk.Client.EmuHawk if (Global.Config.CDLAutoStart) NewFileLogic(); base.OnShown(e); - } - - protected override void OnClosed(EventArgs e) + } + + protected override void OnClosed(EventArgs e) { - //deactivate logger - if (CodeDataLogger != null) //just in case... - CodeDataLogger.SetCDL(null); - } - - private void PCECDL_Load(object sender, EventArgs e) - { - } - - private void PCECDL_DragEnter(object sender, DragEventArgs e) - { - e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None; - } - - private void PCECDL_DragDrop(object sender, DragEventArgs e) - { - var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); - if (Path.GetExtension(filePaths[0]) == ".cdl") - { - LoadFile(filePaths[0]); - } - } - - - - private void tsbViewStyle_SelectedIndexChanged(object sender, EventArgs e) - { - UpdateDisplay(true); - } - - private void tsbLoggingActive_CheckedChanged(object sender, EventArgs e) - { - if (tsbLoggingActive.Checked && _cdl == null) - { - //implicitly create a new file - NewFileLogic(); - } - - if (_cdl != null && tsbLoggingActive.Checked) - CodeDataLogger.SetCDL(_cdl); - else - CodeDataLogger.SetCDL(null); - } - - private void lvCDL_QueryItemText(int item, int subItem, out string text) - { - text = listContents[item][subItem]; - } - - private void tsbExportText_Click(object sender, EventArgs e) - { - StringWriter sw = new StringWriter(); - foreach(var line in listContents) - { - foreach (var entry in line) - sw.Write("{0} |", entry); - sw.WriteLine(); - } - Clipboard.SetText(sw.ToString()); + //deactivate logger + if (CodeDataLogger != null) //just in case... + CodeDataLogger.SetCDL(null); + } + + private void PCECDL_Load(object sender, EventArgs e) + { + } + + private void PCECDL_DragEnter(object sender, DragEventArgs e) + { + e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None; + } + + private void PCECDL_DragDrop(object sender, DragEventArgs e) + { + var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); + if (Path.GetExtension(filePaths[0]) == ".cdl") + { + LoadFile(filePaths[0]); + } + } + + + + private void tsbViewStyle_SelectedIndexChanged(object sender, EventArgs e) + { + UpdateDisplay(true); + } + + private void tsbLoggingActive_CheckedChanged(object sender, EventArgs e) + { + if (tsbLoggingActive.Checked && _cdl == null) + { + //implicitly create a new file + NewFileLogic(); + } + + if (_cdl != null && tsbLoggingActive.Checked) + CodeDataLogger.SetCDL(_cdl); + else + CodeDataLogger.SetCDL(null); + } + + private void lvCDL_QueryItemText(int item, int subItem, out string text) + { + text = listContents[item][subItem]; + } + + private void tsbExportText_Click(object sender, EventArgs e) + { + StringWriter sw = new StringWriter(); + foreach(var line in listContents) + { + foreach (var entry in line) + sw.Write("{0} |", entry); + sw.WriteLine(); + } + Clipboard.SetText(sw.ToString()); } private void miAutoSave_Click(object sender, EventArgs e) @@ -522,6 +522,6 @@ namespace BizHawk.Client.EmuHawk Global.Config.CDLAutoStart ^= true; } - - } -} + + } +} diff --git a/BizHawk.Client.EmuHawk/tools/HexEditor/NewHexEditor.cs b/BizHawk.Client.EmuHawk/tools/HexEditor/NewHexEditor.cs index 761cff4e55..3a5570d819 100644 --- a/BizHawk.Client.EmuHawk/tools/HexEditor/NewHexEditor.cs +++ b/BizHawk.Client.EmuHawk/tools/HexEditor/NewHexEditor.cs @@ -1,105 +1,105 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Windows.Forms; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Client.EmuHawk -{ - public partial class NewHexEditor : Form, IToolFormAutoConfig - { - #region Initialize and Dependencies - - [RequiredService] - private IMemoryDomains MemoryDomains { get; set; } - - [RequiredService] - private IEmulator Emulator { get; set; } - - public NewHexEditor() - { - InitializeComponent(); - - Closing += (o, e) => SaveConfigSettings(); - - HexViewControl.QueryIndexValue += HexView_QueryIndexValue; - HexViewControl.QueryIndexForeColor += HexView_QueryIndexForeColor; - HexViewControl.QueryIndexBgColor += HexView_QueryIndexForeColor; - } - - private void NewHexEditor_Load(object sender, EventArgs e) - { - HexViewControl.ArrayLength = MemoryDomains.MainMemory.Size; - } - - private void SaveConfigSettings() - { - - } - - #endregion - +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class NewHexEditor : Form, IToolFormAutoConfig + { + #region Initialize and Dependencies + + [RequiredService] + private IMemoryDomains MemoryDomains { get; set; } + + [RequiredService] + private IEmulator Emulator { get; set; } + + public NewHexEditor() + { + InitializeComponent(); + + Closing += (o, e) => SaveConfigSettings(); + + HexViewControl.QueryIndexValue += HexView_QueryIndexValue; + HexViewControl.QueryIndexForeColor += HexView_QueryIndexForeColor; + HexViewControl.QueryIndexBgColor += HexView_QueryIndexForeColor; + } + + private void NewHexEditor_Load(object sender, EventArgs e) + { + HexViewControl.ArrayLength = MemoryDomains.MainMemory.Size; + } + + private void SaveConfigSettings() + { + + } + + #endregion + #region IToolForm implementation - public void NewUpdate(ToolFormUpdateType type) { } - - public void UpdateValues() - { - // TODO - } - - public void FastUpdate() - { - // TODO - } - - public void Restart() - { - // TODO - } - - public bool AskSaveChanges() - { - return true; // TODO - } - - public bool UpdateBefore { get { return false; } } - - #endregion - - #region HexView Callbacks - - private void HexView_QueryIndexValue(int index, out long value) - { - value = MemoryDomains.MainMemory.PeekByte(index); - } - - private void HexView_QueryIndexBgColor(int index, ref Color color) - { - color = Color.White; - } - - private void HexView_QueryIndexForeColor(int index, ref Color color) - { - color = Color.Black; - } - - #endregion - - #region Menu Items - - private void FileSubMenu_DropDownOpened(object sender, EventArgs e) - { - - } - - private void ExitMenuItem_Click(object sender, EventArgs e) - { - Close(); - } - - #endregion - } -} + public void NewUpdate(ToolFormUpdateType type) { } + + public void UpdateValues() + { + // TODO + } + + public void FastUpdate() + { + // TODO + } + + public void Restart() + { + // TODO + } + + public bool AskSaveChanges() + { + return true; // TODO + } + + public bool UpdateBefore { get { return false; } } + + #endregion + + #region HexView Callbacks + + private void HexView_QueryIndexValue(int index, out long value) + { + value = MemoryDomains.MainMemory.PeekByte(index); + } + + private void HexView_QueryIndexBgColor(int index, ref Color color) + { + color = Color.White; + } + + private void HexView_QueryIndexForeColor(int index, ref Color color) + { + color = Color.Black; + } + + #endregion + + #region Menu Items + + private void FileSubMenu_DropDownOpened(object sender, EventArgs e) + { + + } + + private void ExitMenuItem_Click(object sender, EventArgs e) + { + Close(); + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs b/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs index 4d0905cf0f..8055a0c5fa 100644 --- a/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs +++ b/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; - -using BizHawk.Emulation.Common.IEmulatorExtensions; - -namespace BizHawk.Emulation.Common +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common.IEmulatorExtensions; + +namespace BizHawk.Emulation.Common { /// /// An implementation of ITraceable that is implementation using only methods @@ -16,42 +16,42 @@ namespace BizHawk.Emulation.Common /// /// /// - public abstract class CallbackBasedTraceBuffer : ITraceable - { - public CallbackBasedTraceBuffer(IDebuggable debuggableCore, IMemoryDomains memoryDomains, IDisassemblable disassembler) - { - if (!debuggableCore.MemoryCallbacksAvailable()) - { - throw new InvalidOperationException("Memory callbacks are required"); - } - - try - { - debuggableCore.GetCpuFlagsAndRegisters(); - } - catch (NotImplementedException) - { - throw new InvalidOperationException("GetCpuFlagsAndRegisters is required"); - } - - Header = "Instructions"; - DebuggableCore = debuggableCore; - MemoryDomains = memoryDomains; - Disassembler = disassembler; - } - - protected readonly IMemoryDomains MemoryDomains; - protected readonly IDisassemblable Disassembler; - protected readonly IDebuggable DebuggableCore; - - protected readonly List Buffer = new List(); - + public abstract class CallbackBasedTraceBuffer : ITraceable + { + public CallbackBasedTraceBuffer(IDebuggable debuggableCore, IMemoryDomains memoryDomains, IDisassemblable disassembler) + { + if (!debuggableCore.MemoryCallbacksAvailable()) + { + throw new InvalidOperationException("Memory callbacks are required"); + } + + try + { + debuggableCore.GetCpuFlagsAndRegisters(); + } + catch (NotImplementedException) + { + throw new InvalidOperationException("GetCpuFlagsAndRegisters is required"); + } + + Header = "Instructions"; + DebuggableCore = debuggableCore; + MemoryDomains = memoryDomains; + Disassembler = disassembler; + } + + protected readonly IMemoryDomains MemoryDomains; + protected readonly IDisassemblable Disassembler; + protected readonly IDebuggable DebuggableCore; + + protected readonly List Buffer = new List(); + public abstract void TraceFromCallback(); private ITraceSink _sink; - public bool Enabled => Sink != null; - + public bool Enabled => Sink != null; + public void Put(TraceInfo info) { Sink.Put(info); @@ -73,26 +73,26 @@ namespace BizHawk.Emulation.Common DebuggableCore.MemoryCallbacks.Add(new TracingMemoryCallback(TraceFromCallback)); } } - } - - public string Header { get; set; } - - public class TracingMemoryCallback : IMemoryCallback - { - public TracingMemoryCallback(Action callback) - { - Callback = callback; - } - - public MemoryCallbackType Type => MemoryCallbackType.Execute; - - public string Name => "Trace Logging"; - - public Action Callback { get; } - - public uint? Address => null; - - public uint? AddressMask => null; - } - } -} + } + + public string Header { get; set; } + + public class TracingMemoryCallback : IMemoryCallback + { + public TracingMemoryCallback(Action callback) + { + Callback = callback; + } + + public MemoryCallbackType Type => MemoryCallbackType.Execute; + + public string Name => "Trace Logging"; + + public Action Callback { get; } + + public uint? Address => null; + + public uint? AddressMask => null; + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs index 903472aa28..67b20cc1e3 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs @@ -1,120 +1,120 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using BizHawk.Emulation.Cores.Computers.Commodore64.Media; - -namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial -{ - public sealed partial class Drive1541 - { - [SaveState.DoNotSave] - private const long LEHMER_RNG_PRIME = 48271; - [SaveState.SaveWithName("DiskDensityCounter")] - private int _diskDensityCounter; // density .. 16 - [SaveState.SaveWithName("DiskSupplementaryCounter")] - private int _diskSupplementaryCounter; // 0 .. 16 - [SaveState.SaveWithName("DiskFluxReversalDetected")] - private bool _diskFluxReversalDetected; - [SaveState.SaveWithName("DiskBitsRemainingInDataEntry")] - private int _diskBitsLeft; - [SaveState.SaveWithName("DiskDataEntryIndex")] - private int _diskByteOffset; - [SaveState.SaveWithName("DiskDataEntry")] - private int _diskBits; - [SaveState.SaveWithName("DiskCurrentCycle")] - private int _diskCycle; - [SaveState.SaveWithName("DiskDensityConfig")] +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using BizHawk.Emulation.Cores.Computers.Commodore64.Media; + +namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial +{ + public sealed partial class Drive1541 + { + [SaveState.DoNotSave] + private const long LEHMER_RNG_PRIME = 48271; + [SaveState.SaveWithName("DiskDensityCounter")] + private int _diskDensityCounter; // density .. 16 + [SaveState.SaveWithName("DiskSupplementaryCounter")] + private int _diskSupplementaryCounter; // 0 .. 16 + [SaveState.SaveWithName("DiskFluxReversalDetected")] + private bool _diskFluxReversalDetected; + [SaveState.SaveWithName("DiskBitsRemainingInDataEntry")] + private int _diskBitsLeft; + [SaveState.SaveWithName("DiskDataEntryIndex")] + private int _diskByteOffset; + [SaveState.SaveWithName("DiskDataEntry")] + private int _diskBits; + [SaveState.SaveWithName("DiskCurrentCycle")] + private int _diskCycle; + [SaveState.SaveWithName("DiskDensityConfig")] private int _diskDensity; - [SaveState.SaveWithName("PreviousCA1")] - private bool _previousCa1; - [SaveState.SaveWithName("CountsBeforeRandomTransition")] - private int _countsBeforeRandomTransition; - [SaveState.SaveWithName("CurrentRNG")] - private int _rngCurrent; - [SaveState.SaveWithName("Clocks")] - private int _clocks; - [SaveState.SaveWithName("CpuClocks")] - private int _cpuClocks; - - // Lehmer RNG - private void AdvanceRng() - { - if (_rngCurrent == 0) - _rngCurrent = 1; - _rngCurrent = (int)(_rngCurrent * LEHMER_RNG_PRIME % int.MaxValue); - } - - private void ExecuteFlux() + [SaveState.SaveWithName("PreviousCA1")] + private bool _previousCa1; + [SaveState.SaveWithName("CountsBeforeRandomTransition")] + private int _countsBeforeRandomTransition; + [SaveState.SaveWithName("CurrentRNG")] + private int _rngCurrent; + [SaveState.SaveWithName("Clocks")] + private int _clocks; + [SaveState.SaveWithName("CpuClocks")] + private int _cpuClocks; + + // Lehmer RNG + private void AdvanceRng() + { + if (_rngCurrent == 0) + _rngCurrent = 1; + _rngCurrent = (int)(_rngCurrent * LEHMER_RNG_PRIME % int.MaxValue); + } + + private void ExecuteFlux() { // This actually executes the main 16mhz clock - while (_clocks > 0) - { - _clocks--; - - // rotate disk + while (_clocks > 0) + { + _clocks--; + + // rotate disk if (_motorEnabled) - { - if (_disk == null) - { - _diskBitsLeft = 1; - _diskBits = 0; - } - else - { - if (_diskBitsLeft <= 0) - { - _diskByteOffset++; - if (_diskByteOffset == Disk.FluxEntriesPerTrack) - { - _diskByteOffset = 0; - } - _diskBits = _trackImageData[_diskByteOffset]; - _diskBitsLeft = Disk.FluxBitsPerEntry; - } - } - if ((_diskBits & 1) != 0) - { - _countsBeforeRandomTransition = 0; - _diskFluxReversalDetected = true; - } - _diskBits >>= 1; - _diskBitsLeft--; - } - - // random flux transition readings for unformatted data - if (_countsBeforeRandomTransition > 0) - { - _countsBeforeRandomTransition--; - if (_countsBeforeRandomTransition == 0) - { - _diskFluxReversalDetected = true; - AdvanceRng(); - // This constant is what VICE uses. TODO: Determine accuracy. - _countsBeforeRandomTransition = (_rngCurrent % 367) + 33; - } - } - - // flux transition circuitry - if (_diskFluxReversalDetected) - { - _diskDensityCounter = _diskDensity; - _diskSupplementaryCounter = 0; - _diskFluxReversalDetected = false; - if (_countsBeforeRandomTransition == 0) + { + if (_disk == null) { - AdvanceRng(); - // This constant is what VICE uses. TODO: Determine accuracy. - _countsBeforeRandomTransition = (_rngCurrent & 0x1F) + 289; - } - } - - // counter circuitry - if (_diskDensityCounter >= 16) - { - _diskDensityCounter = _diskDensity; + _diskBitsLeft = 1; + _diskBits = 0; + } + else + { + if (_diskBitsLeft <= 0) + { + _diskByteOffset++; + if (_diskByteOffset == Disk.FluxEntriesPerTrack) + { + _diskByteOffset = 0; + } + _diskBits = _trackImageData[_diskByteOffset]; + _diskBitsLeft = Disk.FluxBitsPerEntry; + } + } + if ((_diskBits & 1) != 0) + { + _countsBeforeRandomTransition = 0; + _diskFluxReversalDetected = true; + } + _diskBits >>= 1; + _diskBitsLeft--; + } + + // random flux transition readings for unformatted data + if (_countsBeforeRandomTransition > 0) + { + _countsBeforeRandomTransition--; + if (_countsBeforeRandomTransition == 0) + { + _diskFluxReversalDetected = true; + AdvanceRng(); + // This constant is what VICE uses. TODO: Determine accuracy. + _countsBeforeRandomTransition = (_rngCurrent % 367) + 33; + } + } + + // flux transition circuitry + if (_diskFluxReversalDetected) + { + _diskDensityCounter = _diskDensity; + _diskSupplementaryCounter = 0; + _diskFluxReversalDetected = false; + if (_countsBeforeRandomTransition == 0) + { + AdvanceRng(); + // This constant is what VICE uses. TODO: Determine accuracy. + _countsBeforeRandomTransition = (_rngCurrent & 0x1F) + 289; + } + } + + // counter circuitry + if (_diskDensityCounter >= 16) + { + _diskDensityCounter = _diskDensity; _diskSupplementaryCounter++; - if ((_diskSupplementaryCounter & 0x3) == 0x2) + if ((_diskSupplementaryCounter & 0x3) == 0x2) { _bitsRemainingInLatchedByte--; _byteReady = false; @@ -144,23 +144,23 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial _overflowFlagDelaySr |= _diskCycle > 6 ? 4 : 2; } } - } - - if (_diskSupplementaryCounter >= 16) - { - _diskSupplementaryCounter = 0; - } - - _cpuClocks--; - if (_cpuClocks <= 0) - { - ExecuteSystem(); - _cpuClocks = 16; - } - + } + + if (_diskSupplementaryCounter >= 16) + { + _diskSupplementaryCounter = 0; + } + + _cpuClocks--; + if (_cpuClocks <= 0) + { + ExecuteSystem(); + _cpuClocks = 16; + } + _diskDensityCounter++; - _diskCycle = (_diskCycle + 1) & 0xF; - } - } - } -} + _diskCycle = (_diskCycle + 1) & 0xF; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPort.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPort.cs index ba6afcc0c3..3186619d33 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPort.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPort.cs @@ -1,7 +1,7 @@ -using System; -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Computers.Commodore64.User +using System; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Computers.Commodore64.User { public sealed class UserPort { @@ -9,67 +9,67 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.User public Func ReadCounter2; public Func ReadHandshake; public Func ReadSerial1; - public Func ReadSerial2; - - private bool _connected; - private UserPortDevice _device; - - public void Connect(UserPortDevice device) - { - _device = device; - _connected = _device != null; - if (_device != null) - { - _device.ReadCounter1 = () => ReadCounter1(); - _device.ReadCounter2 = () => ReadCounter2(); - _device.ReadHandshake = () => ReadHandshake(); - _device.ReadSerial1 = () => ReadSerial1(); - _device.ReadSerial2 = () => ReadSerial2(); - } - } - - public void Disconnect() - { - _connected = false; - _device = null; - } + public Func ReadSerial2; - public void HardReset() - { - if (_connected) - { - _device.HardReset(); + private bool _connected; + private UserPortDevice _device; + + public void Connect(UserPortDevice device) + { + _device = device; + _connected = _device != null; + if (_device != null) + { + _device.ReadCounter1 = () => ReadCounter1(); + _device.ReadCounter2 = () => ReadCounter2(); + _device.ReadHandshake = () => ReadHandshake(); + _device.ReadSerial1 = () => ReadSerial1(); + _device.ReadSerial2 = () => ReadSerial2(); } } - public bool ReadAtn() - { - return !_connected || _device.ReadAtn(); + public void Disconnect() + { + _connected = false; + _device = null; + } + + public void HardReset() + { + if (_connected) + { + _device.HardReset(); + } + } + + public bool ReadAtn() + { + return !_connected || _device.ReadAtn(); } public int ReadData() { - return !_connected ? 0xFF : _device.ReadData(); + return !_connected ? 0xFF : _device.ReadData(); } public bool ReadFlag2() { - return !_connected || _device.ReadFlag2(); + return !_connected || _device.ReadFlag2(); } public bool ReadPa2() { - return !_connected || _device.ReadPa2(); + return !_connected || _device.ReadPa2(); } public bool ReadReset() { - return !_connected || _device.ReadReset(); + return !_connected || _device.ReadReset(); } public void SyncState(Serializer ser) { SaveState.SyncObject(ser, this); } - } -} + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IMemoryDomains.cs index d7180345dd..85cd7669f2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IMemoryDomains.cs @@ -1,133 +1,133 @@ -using System.Collections.Generic; -using System.Linq; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Intellivision -{ - public sealed partial class Intellivision - { - internal IMemoryDomains MemoryDomains; - - private void SetupMemoryDomains() - { - // TODO: is 8bit for byte arrays and 16bit for ushort correct here? - // If ushort is correct, how about little endian? - var domains = new List - { - new MemoryDomainDelegate( - "Main RAM", - ScratchpadRam.Length, - MemoryDomain.Endian.Little, - addr => ScratchpadRam[addr], - (addr, value) => ScratchpadRam[addr] = value, - 1), - new MemoryDomainDelegate( - "Graphics RAM", - GraphicsRam.Length, - MemoryDomain.Endian.Little, - addr => GraphicsRam[addr], - (addr, value) => GraphicsRam[addr] = value, - 1), - new MemoryDomainDelegate( - "Graphics ROM", - GraphicsRom.Length, - MemoryDomain.Endian.Little, - addr => GraphicsRom[addr], - (addr, value) => GraphicsRom[addr] = value, - 1), - new MemoryDomainDelegate( - "System Ram", - SystemRam.Length * 2, - MemoryDomain.Endian.Little, - addr => ReadByteFromShortArray(addr, SystemRam), - (addr, value) => WriteByteToShortArray(addr, value, SystemRam), - 1 - ), - new MemoryDomainDelegate( - "Executive Rom", - ExecutiveRom.Length * 2, - MemoryDomain.Endian.Little, - addr => ReadByteFromShortArray(addr, ExecutiveRom), - (addr, value) => WriteByteToShortArray(addr, value, ExecutiveRom), - 1 - ), - new MemoryDomainDelegate( - "System Bus", - 0X20000, - MemoryDomain.Endian.Little, - addr => PeekSystemBus(addr), - (addr, value) => PokeSystemBus(addr, value), - 1 - ) - }; - - MemoryDomains = new MemoryDomainList(domains); - (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); - } - +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Intellivision +{ + public sealed partial class Intellivision + { + internal IMemoryDomains MemoryDomains; + + private void SetupMemoryDomains() + { + // TODO: is 8bit for byte arrays and 16bit for ushort correct here? + // If ushort is correct, how about little endian? + var domains = new List + { + new MemoryDomainDelegate( + "Main RAM", + ScratchpadRam.Length, + MemoryDomain.Endian.Little, + addr => ScratchpadRam[addr], + (addr, value) => ScratchpadRam[addr] = value, + 1), + new MemoryDomainDelegate( + "Graphics RAM", + GraphicsRam.Length, + MemoryDomain.Endian.Little, + addr => GraphicsRam[addr], + (addr, value) => GraphicsRam[addr] = value, + 1), + new MemoryDomainDelegate( + "Graphics ROM", + GraphicsRom.Length, + MemoryDomain.Endian.Little, + addr => GraphicsRom[addr], + (addr, value) => GraphicsRom[addr] = value, + 1), + new MemoryDomainDelegate( + "System Ram", + SystemRam.Length * 2, + MemoryDomain.Endian.Little, + addr => ReadByteFromShortArray(addr, SystemRam), + (addr, value) => WriteByteToShortArray(addr, value, SystemRam), + 1 + ), + new MemoryDomainDelegate( + "Executive Rom", + ExecutiveRom.Length * 2, + MemoryDomain.Endian.Little, + addr => ReadByteFromShortArray(addr, ExecutiveRom), + (addr, value) => WriteByteToShortArray(addr, value, ExecutiveRom), + 1 + ), + new MemoryDomainDelegate( + "System Bus", + 0X20000, + MemoryDomain.Endian.Little, + addr => PeekSystemBus(addr), + (addr, value) => PokeSystemBus(addr, value), + 1 + ) + }; + + MemoryDomains = new MemoryDomainList(domains); + (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); + } + private byte PeekSystemBus(long addr) { - if (addr % 2 == 0) - { + if (addr % 2 == 0) + { long index = addr / 2; return (byte)(ReadMemory((ushort)index, true) >> 8); - } - else - { - long index = (addr - 1) / 2; - return (byte)(ReadMemory((ushort)index, true) & 0xFF); } - } - + else + { + long index = (addr - 1) / 2; + return (byte)(ReadMemory((ushort)index, true) & 0xFF); + } + } + private void PokeSystemBus(long addr, byte value) { - if (addr % 2 == 0) - { + if (addr % 2 == 0) + { long index = addr / 2; int temp = (ReadMemory((ushort)index, true) >> 8); WriteMemory((ushort)index, (ushort)(temp & (value << 8)), true); - } - else - { - long index = (addr - 1) / 2; - int temp = ((ReadMemory((ushort)index, true) & 0xFF)<<8); - WriteMemory((ushort)index, (ushort)(temp & value), true); + } + else + { + long index = (addr - 1) / 2; + int temp = ((ReadMemory((ushort)index, true) & 0xFF)<<8); + WriteMemory((ushort)index, (ushort)(temp & value), true); } } // TODO: move these to a common library and maybe add an endian parameter // Little endian - private byte ReadByteFromShortArray(long addr, ushort[] array) - { - if (addr % 2 == 0) - { - long index = addr / 2; - return (byte)(array[index] >> 8); - - } - else - { - long index = (addr - 1) / 2; - return (byte)(array[index] & 0xFF); - } - } - - private void WriteByteToShortArray(long addr, byte value, ushort[] array) - { - if (addr % 2 == 0) - { - long index = (addr - 1) / 2; - ushort val = (ushort)((value << 8) + (array[index] & 0xFF)); - array[index] = val; - - } - else - { - long index = addr / 2; - ushort val = (ushort)((((array[index] >> 8) & 0xFF) << 8) + value); - array[index] = val; - } - } - } -} + private byte ReadByteFromShortArray(long addr, ushort[] array) + { + if (addr % 2 == 0) + { + long index = addr / 2; + return (byte)(array[index] >> 8); + + } + else + { + long index = (addr - 1) / 2; + return (byte)(array[index] & 0xFF); + } + } + + private void WriteByteToShortArray(long addr, byte value, ushort[] array) + { + if (addr % 2 == 0) + { + long index = (addr - 1) / 2; + ushort val = (ushort)((value << 8) + (array[index] & 0xFF)); + array[index] = val; + + } + else + { + long index = addr / 2; + ushort val = (ushort)((((array[index] >> 8) & 0xFF) << 8) + value); + array[index] = val; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper121.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper121.cs index eabd01323f..2f589102ec 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper121.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper121.cs @@ -1,60 +1,60 @@ -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.NES -{ - // Adapted from Nestopia src - public sealed class Mapper121 : MMC3Board_Base - { - private ByteBuffer exRegs = new ByteBuffer(3); - - private readonly byte[] lut = { 0x00, 0x83, 0x42, 0x00 }; - - public override bool Configure(NES.EDetectionOrigin origin) - { - switch (Cart.board_type) - { - case "MAPPER121": - break; - default: - return false; - } - - BaseSetup(); - return true; - } - +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + // Adapted from Nestopia src + public sealed class Mapper121 : MMC3Board_Base + { + private ByteBuffer exRegs = new ByteBuffer(3); + + private readonly byte[] lut = { 0x00, 0x83, 0x42, 0x00 }; + + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER121": + break; + default: + return false; + } + + BaseSetup(); + return true; + } + public override void Dispose() { exRegs.Dispose(); base.Dispose(); - } - - public override void SyncState(Serializer ser) - { - base.SyncState(ser); - ser.Sync("exRegs", ref exRegs); - } - - public override byte ReadEXP(int addr) - { - if (addr >= 0x1000) - { - return exRegs[2]; - } - else - { - return base.ReadEXP(addr); - } } - public override void WriteEXP(int addr, byte value) - { + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + ser.Sync("exRegs", ref exRegs); + } + + public override byte ReadEXP(int addr) + { + if (addr >= 0x1000) + { + return exRegs[2]; + } + else + { + return base.ReadEXP(addr); + } + } + + public override void WriteEXP(int addr, byte value) + { if (addr >= 0x1000) // 0x5000-0x5FFF - { - exRegs[2] = lut[value & 0x3]; - } - } - + { + exRegs[2] = lut[value & 0x3]; + } + } + public override byte ReadPRG(int addr) { int bank_8k = addr >> 13; @@ -73,38 +73,38 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES bank_8k &= prg_mask; addr = (bank_8k << 13) | (addr & 0x1FFF); return ROM[addr]; - } - - public override void WritePRG(int addr, byte value) - { - if (addr < 0x2000) - { - if ((addr & 3) == 3) - { - switch (value) - { - case 0x28: exRegs[0] = 0x0C; break; - case 0x26: exRegs[1] = 0x08; break; - case 0xAB: exRegs[1] = 0x07; break; - case 0xEC: exRegs[1] = 0x0D; break; - case 0xEF: exRegs[1] = 0x0D; break; - case 0xFF: exRegs[1] = 0x09; break; - - case 0x20: exRegs[1] = 0x13; break; - case 0x29: exRegs[1] = 0x1B; break; - - default: exRegs[0] = 0x0; exRegs[1] = 0x0; break; - } - } + } + + public override void WritePRG(int addr, byte value) + { + if (addr < 0x2000) + { + if ((addr & 3) == 3) + { + switch (value) + { + case 0x28: exRegs[0] = 0x0C; break; + case 0x26: exRegs[1] = 0x08; break; + case 0xAB: exRegs[1] = 0x07; break; + case 0xEC: exRegs[1] = 0x0D; break; + case 0xEF: exRegs[1] = 0x0D; break; + case 0xFF: exRegs[1] = 0x09; break; + + case 0x20: exRegs[1] = 0x13; break; + case 0x29: exRegs[1] = 0x1B; break; + + default: exRegs[0] = 0x0; exRegs[1] = 0x0; break; + } + } else if ((addr & 1)>0) - base.WritePRG(addr, value); - else //if (addr==0) - base.WritePRG(0, value); - } - else - { - base.WritePRG(addr, value); - } - } - } -} + base.WritePRG(addr, value); + else //if (addr==0) + base.WritePRG(0, value); + } + else + { + base.WritePRG(addr, value); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper219.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper219.cs index 857236e435..477ffd3ef9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper219.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper219.cs @@ -1,6 +1,6 @@ -namespace BizHawk.Emulation.Cores.Nintendo.NES -{ - public sealed class Mapper219 : MMC3Board_Base +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + public sealed class Mapper219 : MMC3Board_Base { public byte[] exregs = new byte[3]; public byte[] prgregs = new byte[4]; @@ -8,22 +8,22 @@ public byte bits_rev, reg_value; - public override bool Configure(NES.EDetectionOrigin origin) - { - switch (Cart.board_type) - { - case "MAPPER219": - break; - default: - return false; - } - - BaseSetup(); - - prgregs[1] = 1; - prgregs[2] = 2; - prgregs[3] = 3; - + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER219": + break; + default: + return false; + } + + BaseSetup(); + + prgregs[1] = 1; + prgregs[2] = 2; + prgregs[3] = 3; + byte r0_0 = (byte)(0 & ~1); byte r0_1 = (byte)(0 | 1); byte r1_0 = (byte)(2 & ~1); @@ -46,11 +46,11 @@ chr_regs_1k[4] = regs[2]; chr_regs_1k[5] = regs[3]; chr_regs_1k[6] = regs[4]; - chr_regs_1k[7] = regs[5];*/ - - return true; - } - + chr_regs_1k[7] = regs[5];*/ + + return true; + } + public override void WritePRG(int addr, byte value) { if (addr<0x2000) @@ -103,8 +103,8 @@ } else base.WritePRG(addr, value); - } - + } + public override byte ReadPRG(int addr) { int bank_prg = addr >> 13; @@ -122,8 +122,8 @@ } else return base.ReadPPU(addr); - } - + } + public override void WritePPU(int addr, byte value) { if (addr < 0x2000) @@ -134,6 +134,6 @@ } else base.WritePPU(addr, value); - } - } -} + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper223.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper223.cs index bb4d9e908a..4175440a11 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper223.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper223.cs @@ -1,27 +1,27 @@ -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.NES -{ - // TODO - public sealed class Mapper223 : MMC3Board_Base - { - public override bool Configure(NES.EDetectionOrigin origin) - { - switch (Cart.board_type) - { - case "MAPPER223": - break; - default: - return false; - } - - BaseSetup(); - +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + // TODO + public sealed class Mapper223 : MMC3Board_Base + { + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER223": + break; + default: + return false; + } + + BaseSetup(); + mmc3.wram_enable = true; - mmc3.wram_write_protect = true; - return true; - } - + mmc3.wram_write_protect = true; + return true; + } + public override void WriteEXP(int addr, byte value) { if (addr>0x1000) @@ -30,8 +30,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } else base.WriteEXP(addr, value); - } - + } + public override byte ReadEXP(int addr) { if (addr > 0x1000) @@ -40,6 +40,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } else return base.ReadEXP(addr); - } - } -} + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper125.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper125.cs index c6753cf6d5..50d5f1b4f4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper125.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper125.cs @@ -1,72 +1,72 @@ -using BizHawk.Common; - - -namespace BizHawk.Emulation.Cores.Nintendo.NES -{ - public sealed class Mapper125 : NES.NESBoardBase - { - private byte reg; - private int prg_bank_mask_8k; - - public override bool Configure(NES.EDetectionOrigin origin) - { - - switch (Cart.board_type) - { - case "MAPPER125": - case "UNIF_UNL-LH32": - break; - default: - return false; - } - - SetMirrorType(Cart.pad_h, Cart.pad_v); - - prg_bank_mask_8k = Cart.prg_size / 8 - 1; - return true; - } - - public override void SyncState(Serializer ser) - { - ser.Sync("reg", ref reg); - base.SyncState(ser); - } - - public override void WriteWRAM(int addr, byte value) - { - if (addr == 0) - { - reg = value; - } - } - +using BizHawk.Common; + + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + public sealed class Mapper125 : NES.NESBoardBase + { + private byte reg; + private int prg_bank_mask_8k; + + public override bool Configure(NES.EDetectionOrigin origin) + { + + switch (Cart.board_type) + { + case "MAPPER125": + case "UNIF_UNL-LH32": + break; + default: + return false; + } + + SetMirrorType(Cart.pad_h, Cart.pad_v); + + prg_bank_mask_8k = Cart.prg_size / 8 - 1; + return true; + } + + public override void SyncState(Serializer ser) + { + ser.Sync("reg", ref reg); + base.SyncState(ser); + } + + public override void WriteWRAM(int addr, byte value) + { + if (addr == 0) + { + reg = value; + } + } + public override void WritePRG(int addr, byte value) { if ((addr >= 0x4000) && (addr < 0x6000)) WRAM[addr - 0x4000] = value; else base.WritePRG(addr, value); - } - - public override byte ReadPRG(int addr) - { - int bank = 0; - if (addr < 0x2000) { bank = prg_bank_mask_8k - 3; } + } + + public override byte ReadPRG(int addr) + { + int bank = 0; + if (addr < 0x2000) { bank = prg_bank_mask_8k - 3; } else if (addr < 0x4000) { bank = prg_bank_mask_8k - 2; } // for some reason WRAM is mapped to here. else if (addr < 0x6000) { return WRAM[addr - 0x4000]; - } - else { bank = prg_bank_mask_8k; } - - bank &= prg_bank_mask_8k; - return ROM[(bank << 13) + (addr & 0x1FFF)]; - } - - public override byte ReadWRAM(int addr) - { - return ROM[((reg & prg_bank_mask_8k) << 13) + addr]; - } - } -} + } + else { bank = prg_bank_mask_8k; } + + bank &= prg_bank_mask_8k; + return ROM[(bank << 13) + (addr & 0x1FFF)]; + } + + public override byte ReadWRAM(int addr) + { + return ROM[((reg & prg_bank_mask_8k) << 13) + addr]; + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper142.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper142.cs index c976c8ab30..01c50279cc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper142.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper142.cs @@ -1,128 +1,128 @@ using BizHawk.Common; -namespace BizHawk.Emulation.Cores.Nintendo.NES -{ - public sealed class Mapper142 : NES.NESBoardBase - { - private ByteBuffer reg = new ByteBuffer(8); - private byte cmd; - private int lastBank; - - private bool isirqused = false; - private byte IRQa = 0; - private int IRQCount = 0; - - public override bool Configure(NES.EDetectionOrigin origin) - { - switch (Cart.board_type) - { - case "MAPPER142": - case "UNIF_UNL-KS7032": - break; - default: - return false; - } - SetMirrorType(EMirrorType.Horizontal); - lastBank = Cart.prg_size / 8 - 1; - - return true; - } - +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + public sealed class Mapper142 : NES.NESBoardBase + { + private ByteBuffer reg = new ByteBuffer(8); + private byte cmd; + private int lastBank; + + private bool isirqused = false; + private byte IRQa = 0; + private int IRQCount = 0; + + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER142": + case "UNIF_UNL-KS7032": + break; + default: + return false; + } + SetMirrorType(EMirrorType.Horizontal); + lastBank = Cart.prg_size / 8 - 1; + + return true; + } + public override void Dispose() { reg.Dispose(); base.Dispose(); - } - - public override byte ReadWRAM(int addr) + } + + public override byte ReadWRAM(int addr) { - return ROM[(reg[4] << 13) + (addr & 0x1FFF)]; - } - - public override byte ReadPRG(int addr) + return ROM[(reg[4] << 13) + (addr & 0x1FFF)]; + } + + public override byte ReadPRG(int addr) { if (addr < 0x2000) { return ROM[(reg[1] << 13) + (addr & 0x1FFF)]; } if (addr < 0x4000) { return ROM[(reg[2] << 13) + (addr & 0x1FFF)]; } if (addr < 0x6000) { return ROM[(reg[3] << 13) + (addr & 0x1FFF)]; } - return ROM[(lastBank << 13) + (addr & 0x1FFF)]; - } - - public override void WriteEXP(int addr, byte value) - { - Write(addr + 0x4000, value); - } - - public override void WriteWRAM(int addr, byte value) - { - Write(addr + 0x6000, value); - } - - public override void WritePRG(int addr, byte value) - { - Write(addr + 0x8000, value); - } - - private void IRQHook(int a) - { - if (IRQa > 0) - { - IRQCount += a; - if (IRQCount >= 0xFFFF) - { - IRQa = 0; - IRQCount = 0; - - IRQSignal = true; - } - } - } - - public override void ClockPPU() - { - IRQHook(1); - } - - private void Write(int addr, byte value) - { - switch (addr & 0xF000) - { - case 0x8000: - IRQSignal = false; - IRQCount = (IRQCount & 0x000F) | (value & 0x0F); - isirqused = true; - break; - case 0x9000: - IRQSignal = false; - IRQCount = (IRQCount & 0x00F0) | ((value & 0x0F) << 4); - isirqused = true; - break; - case 0xA000: - IRQSignal = false; - IRQCount = (IRQCount & 0x0F00) | ((value & 0x0F) << 8); - isirqused = true; - break; - case 0xB000: - IRQSignal = false; - IRQCount = (IRQCount & 0xF000) | (value << 12); - isirqused = true; - break; - case 0xC000: - if (isirqused) - { - IRQSignal = false; - IRQa = 1; - } - break; - - case 0xE000: - cmd = (byte)(value & 7); - break; - case 0xF000: - reg[cmd] = value; - break; - } - } - } -} + return ROM[(lastBank << 13) + (addr & 0x1FFF)]; + } + + public override void WriteEXP(int addr, byte value) + { + Write(addr + 0x4000, value); + } + + public override void WriteWRAM(int addr, byte value) + { + Write(addr + 0x6000, value); + } + + public override void WritePRG(int addr, byte value) + { + Write(addr + 0x8000, value); + } + + private void IRQHook(int a) + { + if (IRQa > 0) + { + IRQCount += a; + if (IRQCount >= 0xFFFF) + { + IRQa = 0; + IRQCount = 0; + + IRQSignal = true; + } + } + } + + public override void ClockPPU() + { + IRQHook(1); + } + + private void Write(int addr, byte value) + { + switch (addr & 0xF000) + { + case 0x8000: + IRQSignal = false; + IRQCount = (IRQCount & 0x000F) | (value & 0x0F); + isirqused = true; + break; + case 0x9000: + IRQSignal = false; + IRQCount = (IRQCount & 0x00F0) | ((value & 0x0F) << 4); + isirqused = true; + break; + case 0xA000: + IRQSignal = false; + IRQCount = (IRQCount & 0x0F00) | ((value & 0x0F) << 8); + isirqused = true; + break; + case 0xB000: + IRQSignal = false; + IRQCount = (IRQCount & 0xF000) | (value << 12); + isirqused = true; + break; + case 0xC000: + if (isirqused) + { + IRQSignal = false; + IRQa = 1; + } + break; + + case 0xE000: + cmd = (byte)(value & 7); + break; + case 0xF000: + reg[cmd] = value; + break; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/Nes_NTSC_Colors.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/Nes_NTSC_Colors.cs index 063c727e14..07c18fbd64 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/Nes_NTSC_Colors.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/Nes_NTSC_Colors.cs @@ -29,12 +29,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES static readonly float[] hi_levels = { 0.40f, 0.68f, 1.00f, 1.00f }; static readonly byte[] tints = { 0, 6, 10, 8, 2, 4, 0, 0 }; - static readonly float[] phases = - { - -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, - 1.0f, 0.866025f, 0.5f, 0.0f, -0.5f, -0.866025f, - -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, - 1.0f + static readonly float[] phases = + { + -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, + 1.0f, 0.866025f, 0.5f, 0.0f, -0.5f, -0.866025f, + -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, + 1.0f }; public static void Emphasis(byte[] inp, byte[] outp, int entrynum) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.ISettable.cs index ff6a0663a7..6a9eff6c1c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.ISettable.cs @@ -1,278 +1,278 @@ -using System; -using System.ComponentModel; -using System.Globalization; - -using BizHawk.Common; -using BizHawk.Emulation.Common; -using Newtonsoft.Json; - - -namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx -{ - public partial class GPGX : ISettable - { - public GPGXSettings GetSettings() - { - return _settings.Clone(); - } - - public GPGXSyncSettings GetSyncSettings() - { - return _syncSettings.Clone(); - } - - public bool PutSettings(GPGXSettings o) - { - bool ret = GPGXSettings.NeedsReboot(_settings, o); - _settings = o; - LibGPGX.gpgx_set_draw_mask(_settings.GetDrawMask()); - return ret; - } - - public bool PutSyncSettings(GPGXSyncSettings o) - { - bool ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o); - _syncSettings = o; - return ret; - } - - private class UintToHexConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - { - return true; - } - else - { - return base.CanConvertFrom(context, sourceType); - } - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(string)) - { - return true; - } - else - { - return base.CanConvertTo(context, destinationType); - } - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string) && value.GetType() == typeof(uint)) - { - return string.Format("0x{0:x8}", value); - } - else - { - return base.ConvertTo(context, culture, value, destinationType); - } - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value.GetType() == typeof(string)) - { - string input = (string)value; - if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) - { - input = input.Substring(2); - } - return uint.Parse(input, NumberStyles.HexNumber, culture); - } - else - { - return base.ConvertFrom(context, culture, value); - } - } - } - - private GPGXSyncSettings _syncSettings; - private GPGXSettings _settings; - - public class GPGXSettings - { - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGA; - - [DisplayName("Background Layer A")] - [Description("True to draw BG layer A")] - [DefaultValue(true)] - public bool DrawBGA { get { return _DrawBGA; } set { _DrawBGA = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGB; - - [DisplayName("Background Layer B")] - [Description("True to draw BG layer B")] - [DefaultValue(true)] - public bool DrawBGB { get { return _DrawBGB; } set { _DrawBGB = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGW; - - [DisplayName("Background Layer W")] - [Description("True to draw BG layer W")] - [DefaultValue(true)] - public bool DrawBGW { get { return _DrawBGW; } set { _DrawBGW = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawObj; - - [DisplayName("Sprite Layer")] - [Description("True to draw sprite layer")] - [DefaultValue(true)] - public bool DrawObj { get { return _DrawObj; } set { _DrawObj = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] +using System; +using System.ComponentModel; +using System.Globalization; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using Newtonsoft.Json; + + +namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx +{ + public partial class GPGX : ISettable + { + public GPGXSettings GetSettings() + { + return _settings.Clone(); + } + + public GPGXSyncSettings GetSyncSettings() + { + return _syncSettings.Clone(); + } + + public bool PutSettings(GPGXSettings o) + { + bool ret = GPGXSettings.NeedsReboot(_settings, o); + _settings = o; + LibGPGX.gpgx_set_draw_mask(_settings.GetDrawMask()); + return ret; + } + + public bool PutSyncSettings(GPGXSyncSettings o) + { + bool ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o); + _syncSettings = o; + return ret; + } + + private class UintToHexConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertFrom(context, sourceType); + } + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertTo(context, destinationType); + } + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value.GetType() == typeof(uint)) + { + return string.Format("0x{0:x8}", value); + } + else + { + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value.GetType() == typeof(string)) + { + string input = (string)value; + if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + input = input.Substring(2); + } + return uint.Parse(input, NumberStyles.HexNumber, culture); + } + else + { + return base.ConvertFrom(context, culture, value); + } + } + } + + private GPGXSyncSettings _syncSettings; + private GPGXSettings _settings; + + public class GPGXSettings + { + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGA; + + [DisplayName("Background Layer A")] + [Description("True to draw BG layer A")] + [DefaultValue(true)] + public bool DrawBGA { get { return _DrawBGA; } set { _DrawBGA = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGB; + + [DisplayName("Background Layer B")] + [Description("True to draw BG layer B")] + [DefaultValue(true)] + public bool DrawBGB { get { return _DrawBGB; } set { _DrawBGB = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGW; + + [DisplayName("Background Layer W")] + [Description("True to draw BG layer W")] + [DefaultValue(true)] + public bool DrawBGW { get { return _DrawBGW; } set { _DrawBGW = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawObj; + + [DisplayName("Sprite Layer")] + [Description("True to draw sprite layer")] + [DefaultValue(true)] + public bool DrawObj { get { return _DrawObj; } set { _DrawObj = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] private bool _PadScreen320; [DeepEqualsIgnore] [JsonIgnore] - private bool _AlwaysDoubleSize; - - [DisplayName("Pad screen to 320")] - [Description("Set to True to pad the screen out to be 320 when in 256 wide video modes")] - [DefaultValue(false)] + private bool _AlwaysDoubleSize; + + [DisplayName("Pad screen to 320")] + [Description("Set to True to pad the screen out to be 320 when in 256 wide video modes")] + [DefaultValue(false)] public bool PadScreen320 { get { return _PadScreen320; } set { _PadScreen320 = value; } } [DisplayName("Always double-size")] [Description("Set to True to convert the video to high-resolution mode even when it's low resolution so that the window doesn't change size between game modes")] [DefaultValue(false)] - public bool AlwaysDoubleSize { get { return _AlwaysDoubleSize; } set { _AlwaysDoubleSize = value; } } - - [DisplayName("Audio Filter")] - [DefaultValue(LibGPGX.InitSettings.FilterType.LowPass)] - public LibGPGX.InitSettings.FilterType Filter { get; set; } - - [DisplayName("Low Pass Range")] - [Description("Only active when filter type is lowpass")] - [DefaultValue((ushort)39321)] - public ushort LowPassRange { get; set; } - - [DisplayName("Three band low cutoff")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)880)] - public short LowFreq { get; set; } - - [DisplayName("Three band high cutoff")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)5000)] - public short HighFreq { get; set; } - - [DisplayName("Three band low gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short LowGain { get; set; } - - [DisplayName("Three band mid gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short MidGain { get; set; } - - [DisplayName("Three band high gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short HighGain { get; set; } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _Backdrop; - - [DisplayName("Use custom backdrop color")] - [Description("Filler when layers are off")] - [DefaultValue((bool)false)] - public bool Backdrop { get { return _Backdrop; } set { _Backdrop = value; } } - - [DisplayName("Custom backdrop color")] - [Description("Magic pink by default. Requires core reboot")] - [TypeConverter(typeof(UintToHexConverter))] - [DefaultValue((uint)0xffff00ff)] - public uint BackdropColor { get; set; } - - public GPGXSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public GPGXSettings Clone() - { - return (GPGXSettings)MemberwiseClone(); - } - - public LibGPGX.DrawMask GetDrawMask() - { - LibGPGX.DrawMask ret = 0; - if (DrawBGA) ret |= LibGPGX.DrawMask.BGA; - if (DrawBGB) ret |= LibGPGX.DrawMask.BGB; - if (DrawBGW) ret |= LibGPGX.DrawMask.BGW; - if (DrawObj) ret |= LibGPGX.DrawMask.Obj; - if (Backdrop) ret |= LibGPGX.DrawMask.Backdrop; - return ret; - } - - public static bool NeedsReboot(GPGXSettings x, GPGXSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - - public LibGPGX.InitSettings GetNativeSettings() - { - return new LibGPGX.InitSettings - { - Filter = Filter, - LowPassRange = LowPassRange, - LowFreq = LowFreq, - HighFreq = HighFreq, - LowGain = LowGain, - MidGain = MidGain, - HighGain = HighGain, - BackdropColor = BackdropColor - }; - } - } - - public class GPGXSyncSettings - { - [DisplayName("Use Six Button Controllers")] - [Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")] - [DefaultValue(true)] - public bool UseSixButton { get; set; } - - [DisplayName("Control Type")] - [Description("Sets the type of controls that are plugged into the console. Some games will automatically load with a different control type.")] - [DefaultValue(ControlType.Normal)] - public ControlType ControlType { get; set; } - - [DisplayName("Autodetect Region")] - [Description("Sets the region of the emulated console. Many games can run on multiple regions and will behave differently on different ones. Some games may require a particular region.")] - [DefaultValue(LibGPGX.Region.Autodetect)] - public LibGPGX.Region Region { get; set; } - - public GPGXSyncSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public GPGXSyncSettings Clone() - { - return (GPGXSyncSettings)MemberwiseClone(); - } - - public static bool NeedsReboot(GPGXSyncSettings x, GPGXSyncSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - } - } -} + public bool AlwaysDoubleSize { get { return _AlwaysDoubleSize; } set { _AlwaysDoubleSize = value; } } + + [DisplayName("Audio Filter")] + [DefaultValue(LibGPGX.InitSettings.FilterType.LowPass)] + public LibGPGX.InitSettings.FilterType Filter { get; set; } + + [DisplayName("Low Pass Range")] + [Description("Only active when filter type is lowpass")] + [DefaultValue((ushort)39321)] + public ushort LowPassRange { get; set; } + + [DisplayName("Three band low cutoff")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)880)] + public short LowFreq { get; set; } + + [DisplayName("Three band high cutoff")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)5000)] + public short HighFreq { get; set; } + + [DisplayName("Three band low gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short LowGain { get; set; } + + [DisplayName("Three band mid gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short MidGain { get; set; } + + [DisplayName("Three band high gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short HighGain { get; set; } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _Backdrop; + + [DisplayName("Use custom backdrop color")] + [Description("Filler when layers are off")] + [DefaultValue((bool)false)] + public bool Backdrop { get { return _Backdrop; } set { _Backdrop = value; } } + + [DisplayName("Custom backdrop color")] + [Description("Magic pink by default. Requires core reboot")] + [TypeConverter(typeof(UintToHexConverter))] + [DefaultValue((uint)0xffff00ff)] + public uint BackdropColor { get; set; } + + public GPGXSettings() + { + SettingsUtil.SetDefaultValues(this); + } + + public GPGXSettings Clone() + { + return (GPGXSettings)MemberwiseClone(); + } + + public LibGPGX.DrawMask GetDrawMask() + { + LibGPGX.DrawMask ret = 0; + if (DrawBGA) ret |= LibGPGX.DrawMask.BGA; + if (DrawBGB) ret |= LibGPGX.DrawMask.BGB; + if (DrawBGW) ret |= LibGPGX.DrawMask.BGW; + if (DrawObj) ret |= LibGPGX.DrawMask.Obj; + if (Backdrop) ret |= LibGPGX.DrawMask.Backdrop; + return ret; + } + + public static bool NeedsReboot(GPGXSettings x, GPGXSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + + public LibGPGX.InitSettings GetNativeSettings() + { + return new LibGPGX.InitSettings + { + Filter = Filter, + LowPassRange = LowPassRange, + LowFreq = LowFreq, + HighFreq = HighFreq, + LowGain = LowGain, + MidGain = MidGain, + HighGain = HighGain, + BackdropColor = BackdropColor + }; + } + } + + public class GPGXSyncSettings + { + [DisplayName("Use Six Button Controllers")] + [Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")] + [DefaultValue(true)] + public bool UseSixButton { get; set; } + + [DisplayName("Control Type")] + [Description("Sets the type of controls that are plugged into the console. Some games will automatically load with a different control type.")] + [DefaultValue(ControlType.Normal)] + public ControlType ControlType { get; set; } + + [DisplayName("Autodetect Region")] + [Description("Sets the region of the emulated console. Many games can run on multiple regions and will behave differently on different ones. Some games may require a particular region.")] + [DefaultValue(LibGPGX.Region.Autodetect)] + public LibGPGX.Region Region { get; set; } + + public GPGXSyncSettings() + { + SettingsUtil.SetDefaultValues(this); + } + + public GPGXSyncSettings Clone() + { + return (GPGXSyncSettings)MemberwiseClone(); + } + + public static bool NeedsReboot(GPGXSyncSettings x, GPGXSyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.IVideoProvider.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.IVideoProvider.cs index 6cbbd8a7f4..f22e2a3906 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.IVideoProvider.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.IVideoProvider.cs @@ -1,54 +1,54 @@ -using System; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx -{ - public partial class GPGX : IVideoProvider - { - public int[] GetVideoBuffer() { return vidbuff; } - - public int VirtualWidth { get { return 320; } } - - public int VirtualHeight { get { return 224; } } - - public int BufferWidth { get { return vwidth; } } - - public int BufferHeight { get { return vheight; } } - - public int BackgroundColor { get { return unchecked((int)0xff000000); } } - - private int[] vidbuff = new int[0]; - private int vwidth; - private int vheight; - - private void UpdateVideoInitial() - { - // hack: you should call update_video() here, but that gives you 256x192 on frame 0 - // and we know that we only use GPGX to emulate genesis games that will always be 320x224 immediately afterwards - - // so instead, just assume a 320x224 size now; if that happens to be wrong, it'll be fixed soon enough. - - vwidth = 320; - vheight = 224; - vidbuff = new int[vwidth * vheight]; - for (int i = 0; i < vidbuff.Length; i++) - vidbuff[i] = unchecked((int)0xff000000); - } - - private unsafe void UpdateVideo() - { - int gppitch, gpwidth, gpheight; - IntPtr src = IntPtr.Zero; - - LibGPGX.gpgx_get_video(out gpwidth, out gpheight, out gppitch, ref src); - - //in case we're receiving high vertical resolution video, we shall double the horizontal resolution to keep the same proportions - //(concept pioneered for snes) - +using System; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx +{ + public partial class GPGX : IVideoProvider + { + public int[] GetVideoBuffer() { return vidbuff; } + + public int VirtualWidth { get { return 320; } } + + public int VirtualHeight { get { return 224; } } + + public int BufferWidth { get { return vwidth; } } + + public int BufferHeight { get { return vheight; } } + + public int BackgroundColor { get { return unchecked((int)0xff000000); } } + + private int[] vidbuff = new int[0]; + private int vwidth; + private int vheight; + + private void UpdateVideoInitial() + { + // hack: you should call update_video() here, but that gives you 256x192 on frame 0 + // and we know that we only use GPGX to emulate genesis games that will always be 320x224 immediately afterwards + + // so instead, just assume a 320x224 size now; if that happens to be wrong, it'll be fixed soon enough. + + vwidth = 320; + vheight = 224; + vidbuff = new int[vwidth * vheight]; + for (int i = 0; i < vidbuff.Length; i++) + vidbuff[i] = unchecked((int)0xff000000); + } + + private unsafe void UpdateVideo() + { + int gppitch, gpwidth, gpheight; + IntPtr src = IntPtr.Zero; + + LibGPGX.gpgx_get_video(out gpwidth, out gpheight, out gppitch, ref src); + + //in case we're receiving high vertical resolution video, we shall double the horizontal resolution to keep the same proportions + //(concept pioneered for snes) + bool dotDouble = (gpheight == 448); //todo: pal? bool lineDouble = false; - vwidth = gpwidth; + vwidth = gpwidth; vheight = gpheight; if (_settings.AlwaysDoubleSize) @@ -61,15 +61,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx } } - if (_settings.PadScreen320 && vwidth == 256) + if (_settings.PadScreen320 && vwidth == 256) vwidth = 320; - int xpad = (vwidth - gpwidth) / 2; + int xpad = (vwidth - gpwidth) / 2; int xpad2 = vwidth - gpwidth - xpad; if (dotDouble) vwidth *= 2; - - if (vidbuff.Length < vwidth * vheight) + + if (vidbuff.Length < vwidth * vheight) vidbuff = new int[vwidth * vheight]; int xskip = 1; @@ -112,8 +112,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx psrc += rinc; } } - } - } - - } -} + } + } + + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.ITraceable.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.ITraceable.cs index d1b0fd348e..00d0fc8e26 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.ITraceable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.ITraceable.cs @@ -1,48 +1,48 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using BizHawk.Emulation.Common; -using BizHawk.Common.NumberExtensions; - -namespace BizHawk.Emulation.Cores.Sony.PSX -{ - public partial class Octoshock - { +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Cores.Sony.PSX +{ + public partial class Octoshock + { public TraceBuffer Tracer { get; private set; } public static string TraceHeader = "R3000A: PC, machine code, mnemonic, operands, registers (GPRs, lo, hi, sr, cause, epc)"; OctoshockDll.ShockCallback_Trace trace_cb; - - public void ShockTraceCallback(IntPtr opaque, uint PC, uint inst, string dis) - { - var regs = GetCpuFlagsAndRegisters(); - StringBuilder sb = new StringBuilder(); - - foreach (var r in regs) - { - if (r.Key != "pc") - sb.Append( - string.Format("{0}:{1} ", - r.Key, - r.Value.Value.ToHexString(r.Value.BitSize / 4))); + + public void ShockTraceCallback(IntPtr opaque, uint PC, uint inst, string dis) + { + var regs = GetCpuFlagsAndRegisters(); + StringBuilder sb = new StringBuilder(); + + foreach (var r in regs) + { + if (r.Key != "pc") + sb.Append( + string.Format("{0}:{1} ", + r.Key, + r.Value.Value.ToHexString(r.Value.BitSize / 4))); } - Tracer.Put(new TraceInfo - { - Disassembly = string.Format("{0:X8}: {1:X8} {2}", PC, inst, dis.PadRight(30)), - RegisterInfo = sb.ToString().Trim() - }); - } - + Tracer.Put(new TraceInfo + { + Disassembly = string.Format("{0:X8}: {1:X8} {2}", PC, inst, dis.PadRight(30)), + RegisterInfo = sb.ToString().Trim() + }); + } + private void ConnectTracer() { - trace_cb = new OctoshockDll.ShockCallback_Trace(ShockTraceCallback); - Tracer = new TraceBuffer() { Header = TraceHeader }; - ServiceProvider = new BasicServiceProvider(this); - (ServiceProvider as BasicServiceProvider).Register(Tracer); - } - } -} + trace_cb = new OctoshockDll.ShockCallback_Trace(ShockTraceCallback); + Tracer = new TraceBuffer() { Header = TraceHeader }; + ServiceProvider = new BasicServiceProvider(this); + (ServiceProvider as BasicServiceProvider).Register(Tracer); + } + } +} diff --git a/BizHawk.Emulation.Cores/Libretro/LibRetro.cs b/BizHawk.Emulation.Cores/Libretro/LibRetro.cs index 16f2e36794..6c5dd30441 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibRetro.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibRetro.cs @@ -1,21 +1,21 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; -using System.Reflection; - -#pragma warning disable 649, 169 - -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores -{ - /// - /// libretro related shims - /// - public class LibRetro : IDisposable - { +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Reflection; + +#pragma warning disable 649, 169 + +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores +{ + /// + /// libretro related shims + /// + public class LibRetro : IDisposable + { public const int RETRO_API_VERSION = 1; public enum RETRO_ROTATION @@ -24,649 +24,649 @@ namespace BizHawk.Emulation.Cores ROTATION_90_CCW = 1, ROTATION_180_CCW = 2, ROTATION_270_CCW = 3, - } - - public enum RETRO_DEVICE - { - NONE = 0, - JOYPAD = 1, - MOUSE = 2, - KEYBOARD = 3, - LIGHTGUN = 4, - ANALOG = 5, - POINTER = 6, - SENSOR_ACCELEROMETER = 7 - }; - - public enum RETRO_DEVICE_ID_JOYPAD - { - B = 0, - Y = 1, - SELECT = 2, - START = 3, - UP = 4, - DOWN = 5, - LEFT = 6, - RIGHT = 7, - A = 8, - X = 9, - L = 10, - R = 11, - L2 = 12, - R2 = 13, - L3 = 14, - R3 = 15 - }; - - public enum RETRO_LOG_LEVEL : int //exact type size is unclear - { - DEBUG = 0, - INFO, - WARN, - ERROR, - - DUMMY = Int32.MaxValue - }; - - public enum RETRO_DEVICE_ID_ANALOG - { - // LEFT / RIGHT? - X = 0, - Y = 1 - }; - - public enum RETRO_DEVICE_ID_MOUSE - { - X = 0, - Y = 1, - LEFT = 2, - RIGHT = 3 - }; - - public enum RETRO_DEVICE_ID_LIGHTGUN - { - X = 0, - Y = 1, - TRIGGER = 2, - CURSOR = 3, - TURBO = 4, - PAUSE = 5, - START = 6 - }; - - public enum RETRO_DEVICE_ID_POINTER - { - X = 0, - Y = 1, - PRESSED = 2 - }; - - public enum RETRO_DEVICE_ID_SENSOR_ACCELEROMETER - { - X = 0, - Y = 1, - Z = 2 - }; - - public enum RETRO_REGION - { - NTSC = 0, - PAL = 1 - }; - - public enum RETRO_MEMORY - { - SAVE_RAM = 0, - RTC = 1, - SYSTEM_RAM = 2, - VIDEO_RAM = 3, - }; - - public enum RETRO_KEY - { - UNKNOWN = 0, - FIRST = 0, - BACKSPACE = 8, - TAB = 9, - CLEAR = 12, - RETURN = 13, - PAUSE = 19, - ESCAPE = 27, - SPACE = 32, - EXCLAIM = 33, - QUOTEDBL = 34, - HASH = 35, - DOLLAR = 36, - AMPERSAND = 38, - QUOTE = 39, - LEFTPAREN = 40, - RIGHTPAREN = 41, - ASTERISK = 42, - PLUS = 43, - COMMA = 44, - MINUS = 45, - PERIOD = 46, - SLASH = 47, - _0 = 48, - _1 = 49, - _2 = 50, - _3 = 51, - _4 = 52, - _5 = 53, - _6 = 54, - _7 = 55, - _8 = 56, - _9 = 57, - COLON = 58, - SEMICOLON = 59, - LESS = 60, - EQUALS = 61, - GREATER = 62, - QUESTION = 63, - AT = 64, - LEFTBRACKET = 91, - BACKSLASH = 92, - RIGHTBRACKET = 93, - CARET = 94, - UNDERSCORE = 95, - BACKQUOTE = 96, - a = 97, - b = 98, - c = 99, - d = 100, - e = 101, - f = 102, - g = 103, - h = 104, - i = 105, - j = 106, - k = 107, - l = 108, - m = 109, - n = 110, - o = 111, - p = 112, - q = 113, - r = 114, - s = 115, - t = 116, - u = 117, - v = 118, - w = 119, - x = 120, - y = 121, - z = 122, - DELETE = 127, - - KP0 = 256, - KP1 = 257, - KP2 = 258, - KP3 = 259, - KP4 = 260, - KP5 = 261, - KP6 = 262, - KP7 = 263, - KP8 = 264, - KP9 = 265, - KP_PERIOD = 266, - KP_DIVIDE = 267, - KP_MULTIPLY = 268, - KP_MINUS = 269, - KP_PLUS = 270, - KP_ENTER = 271, - KP_EQUALS = 272, - - UP = 273, - DOWN = 274, - RIGHT = 275, - LEFT = 276, - INSERT = 277, - HOME = 278, - END = 279, - PAGEUP = 280, - PAGEDOWN = 281, - - F1 = 282, - F2 = 283, - F3 = 284, - F4 = 285, - F5 = 286, - F6 = 287, - F7 = 288, - F8 = 289, - F9 = 290, - F10 = 291, - F11 = 292, - F12 = 293, - F13 = 294, - F14 = 295, - F15 = 296, - - NUMLOCK = 300, - CAPSLOCK = 301, - SCROLLOCK = 302, - RSHIFT = 303, - LSHIFT = 304, - RCTRL = 305, - LCTRL = 306, - RALT = 307, - LALT = 308, - RMETA = 309, - LMETA = 310, - LSUPER = 311, - RSUPER = 312, - MODE = 313, - COMPOSE = 314, - - HELP = 315, - PRINT = 316, - SYSREQ = 317, - BREAK = 318, - MENU = 319, - POWER = 320, - EURO = 321, - UNDO = 322, - - LAST - }; - - [Flags] - public enum RETRO_MOD - { - NONE = 0, - SHIFT = 1, - CTRL = 2, - ALT = 4, - META = 8, - NUMLOCK = 16, - CAPSLOCK = 32, - SCROLLLOCK = 64 - }; - - [Flags] - public enum RETRO_SIMD - { - SSE = (1 << 0), - SSE2 = (1 << 1), - VMX = (1 << 2), - VMX128 = (1 << 3), - AVX = (1 << 4), - NEON = (1 << 5), - SSE3 = (1 << 6), - SSSE3 = (1 << 7), - MMX = (1 << 8), - MMXEXT = (1 << 9), - SSE4 = (1 << 10), - SSE42 = (1 << 11), - AVX2 = (1 << 12), - VFPU = (1 << 13), - PS = (1 << 14), - AES = (1 << 15), - VFPV3 = (1 << 16), - VFPV4 = (1 << 17), - } - - public enum RETRO_ENVIRONMENT - { - SET_ROTATION = 1, - GET_OVERSCAN = 2, - GET_CAN_DUPE = 3, - SET_MESSAGE = 6, - SHUTDOWN = 7, - SET_PERFORMANCE_LEVEL = 8, - GET_SYSTEM_DIRECTORY = 9, - SET_PIXEL_FORMAT = 10, - SET_INPUT_DESCRIPTORS = 11, - SET_KEYBOARD_CALLBACK = 12, - SET_DISK_CONTROL_INTERFACE = 13, - SET_HW_RENDER = 14, - GET_VARIABLE = 15, - SET_VARIABLES = 16, - GET_VARIABLE_UPDATE = 17, - SET_SUPPORT_NO_GAME = 18, - GET_LIBRETRO_PATH = 19, - SET_AUDIO_CALLBACK = 22, - SET_FRAME_TIME_CALLBACK = 21, - GET_RUMBLE_INTERFACE = 23, - GET_INPUT_DEVICE_CAPABILITIES = 24, - //25,26 are experimental - GET_LOG_INTERFACE = 27, - GET_PERF_INTERFACE = 28, - GET_LOCATION_INTERFACE = 29, - GET_CORE_ASSETS_DIRECTORY = 30, - GET_SAVE_DIRECTORY = 31, - SET_SYSTEM_AV_INFO = 32, - SET_PROC_ADDRESS_CALLBACK = 33, - SET_SUBSYSTEM_INFO = 34, - SET_CONTROLLER_INFO = 35, - SET_MEMORY_MAPS = 36 | EXPERIMENTAL, - SET_GEOMETRY = 37, - GET_USERNAME = 38, - GET_LANGUAGE = 39, - - EXPERIMENTAL = 0x10000 - }; - - public enum retro_hw_context_type - { - RETRO_HW_CONTEXT_NONE = 0, - RETRO_HW_CONTEXT_OPENGL = 1, - RETRO_HW_CONTEXT_OPENGLES2 = 2, - RETRO_HW_CONTEXT_OPENGL_CORE = 3, - RETRO_HW_CONTEXT_OPENGLES3 = 4, - RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, - - RETRO_HW_CONTEXT_DUMMY = Int32.MaxValue - }; - - public struct retro_hw_render_callback - { - public uint context_type; //retro_hw_context_type - public IntPtr context_reset; //retro_hw_context_reset_t - public IntPtr get_current_framebuffer; //retro_hw_get_current_framebuffer_t - public IntPtr get_proc_address; //retro_hw_get_proc_address_t - [MarshalAs(UnmanagedType.U1)] public byte depth; - [MarshalAs(UnmanagedType.U1)] public bool stencil; - [MarshalAs(UnmanagedType.U1)] public bool bottom_left_origin; - public uint version_major; - public uint version_minor; - [MarshalAs(UnmanagedType.U1)] public bool cache_context; - public IntPtr context_destroy; //retro_hw_context_reset_t - [MarshalAs(UnmanagedType.U1)] public bool debug_context; - }; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate long retro_hw_context_reset_t(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate IntPtr retro_hw_get_current_framebuffer_t(); - - //not used - //[UnmanagedFunctionPointer(CallingConvention.Cdecl)] - //public delegate void retro_proc_address_t(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate IntPtr retro_hw_get_proc_address_t(string sym); - - struct retro_memory_map - { - public IntPtr descriptors; //retro_memory_descriptor * - public uint num_descriptors; - }; - - struct retro_memory_descriptor - { - ulong flags; - IntPtr ptr; - IntPtr offset; //size_t - IntPtr start; //size_t - IntPtr select; //size_t - IntPtr disconnect; //size_t - IntPtr len; //size_t - string addrspace; - }; - - public enum RETRO_PIXEL_FORMAT - { - XRGB1555 = 0, - XRGB8888 = 1, - RGB565 = 2 - }; - - public struct retro_message - { - public string msg; - public uint frames; - } - - public struct retro_input_descriptor - { - public uint port; - public uint device; - public uint index; - public uint id; - } - - public struct retro_system_info - { - public string library_name; - public string library_version; - public string valid_extensions; - [MarshalAs(UnmanagedType.U1)] - public bool need_fullpath; - [MarshalAs(UnmanagedType.U1)] - public bool block_extract; - } - - public struct retro_game_geometry - { - public uint base_width; - public uint base_height; - public uint max_width; - public uint max_height; - public float aspect_ratio; - } - - public struct retro_system_timing - { - public double fps; - public double sample_rate; - } - - public struct retro_system_av_info - { - public retro_game_geometry geometry; - public retro_system_timing timing; - } - - public struct retro_variable - { - public string key; - public string value; - } - - public struct retro_game_info - { - public string path; - public IntPtr data; - public uint size; - public string meta; - } - - //untested - public struct retro_perf_counter - { - public string ident; - public ulong start; - public ulong total; - public ulong call_cnt; - - [MarshalAs(UnmanagedType.U1)] - public bool registered; - }; - - //perf callbacks - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate long retro_perf_get_time_usec_t(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate long retro_perf_get_counter_t(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate ulong retro_get_cpu_features_t(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void retro_perf_log_t(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void retro_perf_register_t(ref retro_perf_counter counter); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void retro_perf_start_t(ref retro_perf_counter counter); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void retro_perf_stop_t(ref retro_perf_counter counter); - - //for GET_PERF_INTERFACE - public struct retro_perf_callback - { - public retro_perf_get_time_usec_t get_time_usec; - public retro_get_cpu_features_t get_cpu_features; - public retro_perf_get_counter_t get_perf_counter; - public retro_perf_register_t perf_register; - public retro_perf_start_t perf_start; - public retro_perf_stop_t perf_stop; - public retro_perf_log_t perf_log; - } - - #region callback prototypes - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void retro_log_printf_t(RETRO_LOG_LEVEL level, string fmt, IntPtr a0, IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, IntPtr a7, IntPtr a8, IntPtr a9, IntPtr a10, IntPtr a11, IntPtr a12, IntPtr a13, IntPtr a14, IntPtr a15); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - [return:MarshalAs(UnmanagedType.U1)] - public delegate bool retro_environment_t(RETRO_ENVIRONMENT cmd, IntPtr data); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void retro_video_refresh_t(IntPtr data, uint width, uint height, uint pitch); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void retro_audio_sample_t(short left, short right); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint retro_audio_sample_batch_t(IntPtr data, uint frames); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void retro_input_poll_t(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate short retro_input_state_t(uint port, uint device, uint index, uint id); - #endregion - - #region entry point prototypes - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_set_environment(retro_environment_t cb); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_set_video_refresh(retro_video_refresh_t cb); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_set_audio_sample(retro_audio_sample_t cb); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_set_audio_sample_batch(retro_audio_sample_batch_t cb); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_set_input_poll(retro_input_poll_t cb); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_set_input_state(retro_input_state_t cb); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_init(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_deinit(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint epretro_api_version(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_get_system_info(ref retro_system_info info); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_get_system_av_info(ref retro_system_av_info info); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_set_controller_port_device(uint port, uint device); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_reset(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_run(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint epretro_serialize_size(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool epretro_serialize(IntPtr data, uint size); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool epretro_unserialize(IntPtr data, uint size); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_cheat_reset(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_cheat_set(uint index, [MarshalAs(UnmanagedType.U1)]bool enabled, string code); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool epretro_load_game(ref retro_game_info game); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool epretro_load_game_special(uint game_type, ref retro_game_info info, uint num_info); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void epretro_unload_game(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint epretro_get_region(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate IntPtr epretro_get_memory_data(RETRO_MEMORY id); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint epretro_get_memory_size(RETRO_MEMORY id); - #endregion - - #region entry points - // these are all hooked up by reflection on dll load - public epretro_set_environment retro_set_environment; - public epretro_set_video_refresh retro_set_video_refresh; - public epretro_set_audio_sample retro_set_audio_sample; - public epretro_set_audio_sample_batch retro_set_audio_sample_batch; - public epretro_set_input_poll retro_set_input_poll; - public epretro_set_input_state retro_set_input_state; - public epretro_init retro_init; - /// - /// Dispose() calls this, so you shouldn't - /// - public epretro_deinit retro_deinit; - public epretro_api_version retro_api_version; - public epretro_get_system_info retro_get_system_info; - public epretro_get_system_av_info retro_get_system_av_info; - public epretro_set_controller_port_device retro_set_controller_port_device; - public epretro_reset retro_reset; - public epretro_run retro_run; - public epretro_serialize_size retro_serialize_size; - public epretro_serialize retro_serialize; - public epretro_unserialize retro_unserialize; - public epretro_cheat_reset retro_cheat_reset; - public epretro_cheat_set retro_cheat_set; - public epretro_load_game retro_load_game; - public epretro_load_game_special retro_load_game_special; - public epretro_unload_game retro_unload_game; - public epretro_get_region retro_get_region; - public epretro_get_memory_data retro_get_memory_data; - public epretro_get_memory_size retro_get_memory_size; - #endregion - - public void Dispose() - { - dll.Dispose(); - } - - InstanceDll dll; - public LibRetro(string modulename) - { - dll = new InstanceDll(modulename); - if (!ConnectAllEntryPoints()) - { - dll.Dispose(); - throw new Exception("ConnectAllEntryPoints() failed. The console may contain more details."); - } - } - - private static IEnumerable GetAllEntryPoints() - { - return typeof(LibRetro).GetFields().Where((field) => field.FieldType.Name.StartsWith("epretro")); - } - - private void ClearAllEntryPoints() - { - foreach (var field in GetAllEntryPoints()) - { - field.SetValue(this, null); - } - } - - private bool ConnectAllEntryPoints() - { - bool succeed = true; - foreach (var field in GetAllEntryPoints()) - { - string fieldname = field.Name; - IntPtr entry = dll.GetProcAddress(fieldname); - if (entry != IntPtr.Zero) - { - field.SetValue(this, Marshal.GetDelegateForFunctionPointer(entry, field.FieldType)); - } - else - { - Console.WriteLine("Couldn't bind libretro entry point {0}", fieldname); - succeed = false; - } - } - return succeed; - } - } -} + } + + public enum RETRO_DEVICE + { + NONE = 0, + JOYPAD = 1, + MOUSE = 2, + KEYBOARD = 3, + LIGHTGUN = 4, + ANALOG = 5, + POINTER = 6, + SENSOR_ACCELEROMETER = 7 + }; + + public enum RETRO_DEVICE_ID_JOYPAD + { + B = 0, + Y = 1, + SELECT = 2, + START = 3, + UP = 4, + DOWN = 5, + LEFT = 6, + RIGHT = 7, + A = 8, + X = 9, + L = 10, + R = 11, + L2 = 12, + R2 = 13, + L3 = 14, + R3 = 15 + }; + + public enum RETRO_LOG_LEVEL : int //exact type size is unclear + { + DEBUG = 0, + INFO, + WARN, + ERROR, + + DUMMY = Int32.MaxValue + }; + + public enum RETRO_DEVICE_ID_ANALOG + { + // LEFT / RIGHT? + X = 0, + Y = 1 + }; + + public enum RETRO_DEVICE_ID_MOUSE + { + X = 0, + Y = 1, + LEFT = 2, + RIGHT = 3 + }; + + public enum RETRO_DEVICE_ID_LIGHTGUN + { + X = 0, + Y = 1, + TRIGGER = 2, + CURSOR = 3, + TURBO = 4, + PAUSE = 5, + START = 6 + }; + + public enum RETRO_DEVICE_ID_POINTER + { + X = 0, + Y = 1, + PRESSED = 2 + }; + + public enum RETRO_DEVICE_ID_SENSOR_ACCELEROMETER + { + X = 0, + Y = 1, + Z = 2 + }; + + public enum RETRO_REGION + { + NTSC = 0, + PAL = 1 + }; + + public enum RETRO_MEMORY + { + SAVE_RAM = 0, + RTC = 1, + SYSTEM_RAM = 2, + VIDEO_RAM = 3, + }; + + public enum RETRO_KEY + { + UNKNOWN = 0, + FIRST = 0, + BACKSPACE = 8, + TAB = 9, + CLEAR = 12, + RETURN = 13, + PAUSE = 19, + ESCAPE = 27, + SPACE = 32, + EXCLAIM = 33, + QUOTEDBL = 34, + HASH = 35, + DOLLAR = 36, + AMPERSAND = 38, + QUOTE = 39, + LEFTPAREN = 40, + RIGHTPAREN = 41, + ASTERISK = 42, + PLUS = 43, + COMMA = 44, + MINUS = 45, + PERIOD = 46, + SLASH = 47, + _0 = 48, + _1 = 49, + _2 = 50, + _3 = 51, + _4 = 52, + _5 = 53, + _6 = 54, + _7 = 55, + _8 = 56, + _9 = 57, + COLON = 58, + SEMICOLON = 59, + LESS = 60, + EQUALS = 61, + GREATER = 62, + QUESTION = 63, + AT = 64, + LEFTBRACKET = 91, + BACKSLASH = 92, + RIGHTBRACKET = 93, + CARET = 94, + UNDERSCORE = 95, + BACKQUOTE = 96, + a = 97, + b = 98, + c = 99, + d = 100, + e = 101, + f = 102, + g = 103, + h = 104, + i = 105, + j = 106, + k = 107, + l = 108, + m = 109, + n = 110, + o = 111, + p = 112, + q = 113, + r = 114, + s = 115, + t = 116, + u = 117, + v = 118, + w = 119, + x = 120, + y = 121, + z = 122, + DELETE = 127, + + KP0 = 256, + KP1 = 257, + KP2 = 258, + KP3 = 259, + KP4 = 260, + KP5 = 261, + KP6 = 262, + KP7 = 263, + KP8 = 264, + KP9 = 265, + KP_PERIOD = 266, + KP_DIVIDE = 267, + KP_MULTIPLY = 268, + KP_MINUS = 269, + KP_PLUS = 270, + KP_ENTER = 271, + KP_EQUALS = 272, + + UP = 273, + DOWN = 274, + RIGHT = 275, + LEFT = 276, + INSERT = 277, + HOME = 278, + END = 279, + PAGEUP = 280, + PAGEDOWN = 281, + + F1 = 282, + F2 = 283, + F3 = 284, + F4 = 285, + F5 = 286, + F6 = 287, + F7 = 288, + F8 = 289, + F9 = 290, + F10 = 291, + F11 = 292, + F12 = 293, + F13 = 294, + F14 = 295, + F15 = 296, + + NUMLOCK = 300, + CAPSLOCK = 301, + SCROLLOCK = 302, + RSHIFT = 303, + LSHIFT = 304, + RCTRL = 305, + LCTRL = 306, + RALT = 307, + LALT = 308, + RMETA = 309, + LMETA = 310, + LSUPER = 311, + RSUPER = 312, + MODE = 313, + COMPOSE = 314, + + HELP = 315, + PRINT = 316, + SYSREQ = 317, + BREAK = 318, + MENU = 319, + POWER = 320, + EURO = 321, + UNDO = 322, + + LAST + }; + + [Flags] + public enum RETRO_MOD + { + NONE = 0, + SHIFT = 1, + CTRL = 2, + ALT = 4, + META = 8, + NUMLOCK = 16, + CAPSLOCK = 32, + SCROLLLOCK = 64 + }; + + [Flags] + public enum RETRO_SIMD + { + SSE = (1 << 0), + SSE2 = (1 << 1), + VMX = (1 << 2), + VMX128 = (1 << 3), + AVX = (1 << 4), + NEON = (1 << 5), + SSE3 = (1 << 6), + SSSE3 = (1 << 7), + MMX = (1 << 8), + MMXEXT = (1 << 9), + SSE4 = (1 << 10), + SSE42 = (1 << 11), + AVX2 = (1 << 12), + VFPU = (1 << 13), + PS = (1 << 14), + AES = (1 << 15), + VFPV3 = (1 << 16), + VFPV4 = (1 << 17), + } + + public enum RETRO_ENVIRONMENT + { + SET_ROTATION = 1, + GET_OVERSCAN = 2, + GET_CAN_DUPE = 3, + SET_MESSAGE = 6, + SHUTDOWN = 7, + SET_PERFORMANCE_LEVEL = 8, + GET_SYSTEM_DIRECTORY = 9, + SET_PIXEL_FORMAT = 10, + SET_INPUT_DESCRIPTORS = 11, + SET_KEYBOARD_CALLBACK = 12, + SET_DISK_CONTROL_INTERFACE = 13, + SET_HW_RENDER = 14, + GET_VARIABLE = 15, + SET_VARIABLES = 16, + GET_VARIABLE_UPDATE = 17, + SET_SUPPORT_NO_GAME = 18, + GET_LIBRETRO_PATH = 19, + SET_AUDIO_CALLBACK = 22, + SET_FRAME_TIME_CALLBACK = 21, + GET_RUMBLE_INTERFACE = 23, + GET_INPUT_DEVICE_CAPABILITIES = 24, + //25,26 are experimental + GET_LOG_INTERFACE = 27, + GET_PERF_INTERFACE = 28, + GET_LOCATION_INTERFACE = 29, + GET_CORE_ASSETS_DIRECTORY = 30, + GET_SAVE_DIRECTORY = 31, + SET_SYSTEM_AV_INFO = 32, + SET_PROC_ADDRESS_CALLBACK = 33, + SET_SUBSYSTEM_INFO = 34, + SET_CONTROLLER_INFO = 35, + SET_MEMORY_MAPS = 36 | EXPERIMENTAL, + SET_GEOMETRY = 37, + GET_USERNAME = 38, + GET_LANGUAGE = 39, + + EXPERIMENTAL = 0x10000 + }; + + public enum retro_hw_context_type + { + RETRO_HW_CONTEXT_NONE = 0, + RETRO_HW_CONTEXT_OPENGL = 1, + RETRO_HW_CONTEXT_OPENGLES2 = 2, + RETRO_HW_CONTEXT_OPENGL_CORE = 3, + RETRO_HW_CONTEXT_OPENGLES3 = 4, + RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, + + RETRO_HW_CONTEXT_DUMMY = Int32.MaxValue + }; + + public struct retro_hw_render_callback + { + public uint context_type; //retro_hw_context_type + public IntPtr context_reset; //retro_hw_context_reset_t + public IntPtr get_current_framebuffer; //retro_hw_get_current_framebuffer_t + public IntPtr get_proc_address; //retro_hw_get_proc_address_t + [MarshalAs(UnmanagedType.U1)] public byte depth; + [MarshalAs(UnmanagedType.U1)] public bool stencil; + [MarshalAs(UnmanagedType.U1)] public bool bottom_left_origin; + public uint version_major; + public uint version_minor; + [MarshalAs(UnmanagedType.U1)] public bool cache_context; + public IntPtr context_destroy; //retro_hw_context_reset_t + [MarshalAs(UnmanagedType.U1)] public bool debug_context; + }; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate long retro_hw_context_reset_t(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr retro_hw_get_current_framebuffer_t(); + + //not used + //[UnmanagedFunctionPointer(CallingConvention.Cdecl)] + //public delegate void retro_proc_address_t(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr retro_hw_get_proc_address_t(string sym); + + struct retro_memory_map + { + public IntPtr descriptors; //retro_memory_descriptor * + public uint num_descriptors; + }; + + struct retro_memory_descriptor + { + ulong flags; + IntPtr ptr; + IntPtr offset; //size_t + IntPtr start; //size_t + IntPtr select; //size_t + IntPtr disconnect; //size_t + IntPtr len; //size_t + string addrspace; + }; + + public enum RETRO_PIXEL_FORMAT + { + XRGB1555 = 0, + XRGB8888 = 1, + RGB565 = 2 + }; + + public struct retro_message + { + public string msg; + public uint frames; + } + + public struct retro_input_descriptor + { + public uint port; + public uint device; + public uint index; + public uint id; + } + + public struct retro_system_info + { + public string library_name; + public string library_version; + public string valid_extensions; + [MarshalAs(UnmanagedType.U1)] + public bool need_fullpath; + [MarshalAs(UnmanagedType.U1)] + public bool block_extract; + } + + public struct retro_game_geometry + { + public uint base_width; + public uint base_height; + public uint max_width; + public uint max_height; + public float aspect_ratio; + } + + public struct retro_system_timing + { + public double fps; + public double sample_rate; + } + + public struct retro_system_av_info + { + public retro_game_geometry geometry; + public retro_system_timing timing; + } + + public struct retro_variable + { + public string key; + public string value; + } + + public struct retro_game_info + { + public string path; + public IntPtr data; + public uint size; + public string meta; + } + + //untested + public struct retro_perf_counter + { + public string ident; + public ulong start; + public ulong total; + public ulong call_cnt; + + [MarshalAs(UnmanagedType.U1)] + public bool registered; + }; + + //perf callbacks + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate long retro_perf_get_time_usec_t(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate long retro_perf_get_counter_t(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate ulong retro_get_cpu_features_t(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void retro_perf_log_t(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void retro_perf_register_t(ref retro_perf_counter counter); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void retro_perf_start_t(ref retro_perf_counter counter); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void retro_perf_stop_t(ref retro_perf_counter counter); + + //for GET_PERF_INTERFACE + public struct retro_perf_callback + { + public retro_perf_get_time_usec_t get_time_usec; + public retro_get_cpu_features_t get_cpu_features; + public retro_perf_get_counter_t get_perf_counter; + public retro_perf_register_t perf_register; + public retro_perf_start_t perf_start; + public retro_perf_stop_t perf_stop; + public retro_perf_log_t perf_log; + } + + #region callback prototypes + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate void retro_log_printf_t(RETRO_LOG_LEVEL level, string fmt, IntPtr a0, IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, IntPtr a7, IntPtr a8, IntPtr a9, IntPtr a10, IntPtr a11, IntPtr a12, IntPtr a13, IntPtr a14, IntPtr a15); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return:MarshalAs(UnmanagedType.U1)] + public delegate bool retro_environment_t(RETRO_ENVIRONMENT cmd, IntPtr data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void retro_video_refresh_t(IntPtr data, uint width, uint height, uint pitch); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void retro_audio_sample_t(short left, short right); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate uint retro_audio_sample_batch_t(IntPtr data, uint frames); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void retro_input_poll_t(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate short retro_input_state_t(uint port, uint device, uint index, uint id); + #endregion + + #region entry point prototypes + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_set_environment(retro_environment_t cb); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_set_video_refresh(retro_video_refresh_t cb); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_set_audio_sample(retro_audio_sample_t cb); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_set_audio_sample_batch(retro_audio_sample_batch_t cb); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_set_input_poll(retro_input_poll_t cb); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_set_input_state(retro_input_state_t cb); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_init(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_deinit(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate uint epretro_api_version(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_get_system_info(ref retro_system_info info); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_get_system_av_info(ref retro_system_av_info info); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_set_controller_port_device(uint port, uint device); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_reset(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_run(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate uint epretro_serialize_size(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.U1)] + public delegate bool epretro_serialize(IntPtr data, uint size); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.U1)] + public delegate bool epretro_unserialize(IntPtr data, uint size); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_cheat_reset(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_cheat_set(uint index, [MarshalAs(UnmanagedType.U1)]bool enabled, string code); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.U1)] + public delegate bool epretro_load_game(ref retro_game_info game); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.U1)] + public delegate bool epretro_load_game_special(uint game_type, ref retro_game_info info, uint num_info); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void epretro_unload_game(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate uint epretro_get_region(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr epretro_get_memory_data(RETRO_MEMORY id); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate uint epretro_get_memory_size(RETRO_MEMORY id); + #endregion + + #region entry points + // these are all hooked up by reflection on dll load + public epretro_set_environment retro_set_environment; + public epretro_set_video_refresh retro_set_video_refresh; + public epretro_set_audio_sample retro_set_audio_sample; + public epretro_set_audio_sample_batch retro_set_audio_sample_batch; + public epretro_set_input_poll retro_set_input_poll; + public epretro_set_input_state retro_set_input_state; + public epretro_init retro_init; + /// + /// Dispose() calls this, so you shouldn't + /// + public epretro_deinit retro_deinit; + public epretro_api_version retro_api_version; + public epretro_get_system_info retro_get_system_info; + public epretro_get_system_av_info retro_get_system_av_info; + public epretro_set_controller_port_device retro_set_controller_port_device; + public epretro_reset retro_reset; + public epretro_run retro_run; + public epretro_serialize_size retro_serialize_size; + public epretro_serialize retro_serialize; + public epretro_unserialize retro_unserialize; + public epretro_cheat_reset retro_cheat_reset; + public epretro_cheat_set retro_cheat_set; + public epretro_load_game retro_load_game; + public epretro_load_game_special retro_load_game_special; + public epretro_unload_game retro_unload_game; + public epretro_get_region retro_get_region; + public epretro_get_memory_data retro_get_memory_data; + public epretro_get_memory_size retro_get_memory_size; + #endregion + + public void Dispose() + { + dll.Dispose(); + } + + InstanceDll dll; + public LibRetro(string modulename) + { + dll = new InstanceDll(modulename); + if (!ConnectAllEntryPoints()) + { + dll.Dispose(); + throw new Exception("ConnectAllEntryPoints() failed. The console may contain more details."); + } + } + + private static IEnumerable GetAllEntryPoints() + { + return typeof(LibRetro).GetFields().Where((field) => field.FieldType.Name.StartsWith("epretro")); + } + + private void ClearAllEntryPoints() + { + foreach (var field in GetAllEntryPoints()) + { + field.SetValue(this, null); + } + } + + private bool ConnectAllEntryPoints() + { + bool succeed = true; + foreach (var field in GetAllEntryPoints()) + { + string fieldname = field.Name; + IntPtr entry = dll.GetProcAddress(fieldname); + if (entry != IntPtr.Zero) + { + field.SetValue(this, Marshal.GetDelegateForFunctionPointer(entry, field.FieldType)); + } + else + { + Console.WriteLine("Couldn't bind libretro entry point {0}", fieldname); + succeed = false; + } + } + return succeed; + } + } +} diff --git a/BizHawk.Emulation.Cores/Libretro/LibRetroEmulator.cs b/BizHawk.Emulation.Cores/Libretro/LibRetroEmulator.cs index ae5cb9a529..f82d748423 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibRetroEmulator.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibRetroEmulator.cs @@ -1,106 +1,106 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; -using Newtonsoft.Json; - -using BizHawk.Common; -using BizHawk.Emulation.Common; -using BizHawk.Common.BufferExtensions; - -namespace BizHawk.Emulation.Cores -{ - [CoreAttributes("Libretro", "natt&zeromus")] - public unsafe partial class LibRetroEmulator : IEmulator, ISettable, - ISaveRam, IStatable, IVideoProvider, IInputPollable - { - #region Settings - - Settings _Settings = new Settings(); - SyncSettings _SyncSettings; - - public class SyncSettings - { - public SyncSettings Clone() - { - return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(this)); - } - - public SyncSettings() - { - } - } - - - public class Settings - { - public void Validate() - { - } - - public Settings() - { - SettingsUtil.SetDefaultValues(this); - } - - public Settings Clone() - { - return (Settings)MemberwiseClone(); - } - } - - public Settings GetSettings() - { - return _Settings.Clone(); - } - - public SyncSettings GetSyncSettings() - { - return _SyncSettings.Clone(); - } - - public bool PutSettings(Settings o) - { - _Settings.Validate(); - _Settings = o; - - //TODO - store settings into core? or we can just keep doing it before frameadvance - - return false; - } - - public bool PutSyncSettings(SyncSettings o) - { - bool reboot = false; - - //we could do it this way roughly if we need to - //if(JsonConvert.SerializeObject(o.FIOConfig) != JsonConvert.SerializeObject(_SyncSettings.FIOConfig) - - _SyncSettings = o; - - return reboot; - } - - #endregion - - #region callbacks - - unsafe void retro_log_printf(LibRetro.RETRO_LOG_LEVEL level, string fmt, IntPtr a0, IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, IntPtr a7, IntPtr a8, IntPtr a9, IntPtr a10, IntPtr a11, IntPtr a12, IntPtr a13, IntPtr a14, IntPtr a15) - { - //avert your eyes, these things were not meant to be seen in c# - //I'm not sure this is a great idea. It would suck for silly logging to be unstable. But.. I dont think this is unstable. The sprintf might just print some garbledy stuff. - var args = new IntPtr[] { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 }; - int idx = 0; - Console.Write(Sprintf.sprintf(fmt, () => args[idx++])); - } - - unsafe bool retro_environment(LibRetro.RETRO_ENVIRONMENT cmd, IntPtr data) - { - Console.WriteLine(cmd); - switch (cmd) - { +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using Newtonsoft.Json; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Common.BufferExtensions; + +namespace BizHawk.Emulation.Cores +{ + [CoreAttributes("Libretro", "natt&zeromus")] + public unsafe partial class LibRetroEmulator : IEmulator, ISettable, + ISaveRam, IStatable, IVideoProvider, IInputPollable + { + #region Settings + + Settings _Settings = new Settings(); + SyncSettings _SyncSettings; + + public class SyncSettings + { + public SyncSettings Clone() + { + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(this)); + } + + public SyncSettings() + { + } + } + + + public class Settings + { + public void Validate() + { + } + + public Settings() + { + SettingsUtil.SetDefaultValues(this); + } + + public Settings Clone() + { + return (Settings)MemberwiseClone(); + } + } + + public Settings GetSettings() + { + return _Settings.Clone(); + } + + public SyncSettings GetSyncSettings() + { + return _SyncSettings.Clone(); + } + + public bool PutSettings(Settings o) + { + _Settings.Validate(); + _Settings = o; + + //TODO - store settings into core? or we can just keep doing it before frameadvance + + return false; + } + + public bool PutSyncSettings(SyncSettings o) + { + bool reboot = false; + + //we could do it this way roughly if we need to + //if(JsonConvert.SerializeObject(o.FIOConfig) != JsonConvert.SerializeObject(_SyncSettings.FIOConfig) + + _SyncSettings = o; + + return reboot; + } + + #endregion + + #region callbacks + + unsafe void retro_log_printf(LibRetro.RETRO_LOG_LEVEL level, string fmt, IntPtr a0, IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, IntPtr a7, IntPtr a8, IntPtr a9, IntPtr a10, IntPtr a11, IntPtr a12, IntPtr a13, IntPtr a14, IntPtr a15) + { + //avert your eyes, these things were not meant to be seen in c# + //I'm not sure this is a great idea. It would suck for silly logging to be unstable. But.. I dont think this is unstable. The sprintf might just print some garbledy stuff. + var args = new IntPtr[] { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 }; + int idx = 0; + Console.Write(Sprintf.sprintf(fmt, () => args[idx++])); + } + + unsafe bool retro_environment(LibRetro.RETRO_ENVIRONMENT cmd, IntPtr data) + { + Console.WriteLine(cmd); + switch (cmd) + { case LibRetro.RETRO_ENVIRONMENT.SET_ROTATION: { var rotation = (LibRetro.RETRO_ROTATION)(*(int*)data.ToPointer()); @@ -108,758 +108,758 @@ namespace BizHawk.Emulation.Cores if (rotation == LibRetro.RETRO_ROTATION.ROTATION_90_CCW) environmentInfo.Rotation_CCW = 90; if (rotation == LibRetro.RETRO_ROTATION.ROTATION_180_CCW) environmentInfo.Rotation_CCW = 180; if (rotation == LibRetro.RETRO_ROTATION.ROTATION_270_CCW) environmentInfo.Rotation_CCW = 270; - return true; + return true; } - case LibRetro.RETRO_ENVIRONMENT.GET_OVERSCAN: - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_CAN_DUPE: - //gambatte requires this - *(bool*)data.ToPointer() = true; - return true; - case LibRetro.RETRO_ENVIRONMENT.SET_MESSAGE: - { - LibRetro.retro_message msg = new LibRetro.retro_message(); - Marshal.PtrToStructure(data, msg); - if (!string.IsNullOrEmpty(msg.msg)) - Console.WriteLine("LibRetro Message: {0}", msg.msg); - return true; - } - case LibRetro.RETRO_ENVIRONMENT.SHUTDOWN: - return false; - case LibRetro.RETRO_ENVIRONMENT.SET_PERFORMANCE_LEVEL: - Console.WriteLine("Core suggested SET_PERFORMANCE_LEVEL {0}", *(uint*)data.ToPointer()); - return true; - case LibRetro.RETRO_ENVIRONMENT.GET_SYSTEM_DIRECTORY: - //mednafen NGP neopop fails to launch with no system directory - Directory.CreateDirectory(SystemDirectory); //just to be safe, it seems likely that cores will crash without a created system directory - Console.WriteLine("returning system directory: " + SystemDirectory); - *((IntPtr*)data.ToPointer()) = SystemDirectoryAtom; - return true; - case LibRetro.RETRO_ENVIRONMENT.SET_PIXEL_FORMAT: - { - LibRetro.RETRO_PIXEL_FORMAT fmt = 0; - int[] tmp = new int[1]; - Marshal.Copy(data, tmp, 0, 1); - fmt = (LibRetro.RETRO_PIXEL_FORMAT)tmp[0]; - switch (fmt) - { - case LibRetro.RETRO_PIXEL_FORMAT.RGB565: - case LibRetro.RETRO_PIXEL_FORMAT.XRGB1555: - case LibRetro.RETRO_PIXEL_FORMAT.XRGB8888: - pixelfmt = fmt; - Console.WriteLine("New pixel format set: {0}", pixelfmt); - return true; - default: - Console.WriteLine("Unrecognized pixel format: {0}", (int)pixelfmt); - return false; - } - } - case LibRetro.RETRO_ENVIRONMENT.SET_INPUT_DESCRIPTORS: - return false; - case LibRetro.RETRO_ENVIRONMENT.SET_KEYBOARD_CALLBACK: - return false; - case LibRetro.RETRO_ENVIRONMENT.SET_DISK_CONTROL_INTERFACE: - return false; - case LibRetro.RETRO_ENVIRONMENT.SET_HW_RENDER: - { - //mupen64plus needs this, as well as 3dengine - LibRetro.retro_hw_render_callback* info = (LibRetro.retro_hw_render_callback*)data.ToPointer(); - Console.WriteLine("SET_HW_RENDER: {0}, version={1}.{2}, dbg/cache={3}/{4}, depth/stencil = {5}/{6}{7}", info->context_type, info->version_minor, info->version_major, info->debug_context, info->cache_context, info->depth, info->stencil, info->bottom_left_origin ? " (bottomleft)" : ""); - return true; - } - case LibRetro.RETRO_ENVIRONMENT.GET_VARIABLE: - { - void** variables = (void**)data.ToPointer(); - IntPtr pKey = new IntPtr(*variables++); - string key = Marshal.PtrToStringAnsi(pKey); - Console.WriteLine("Requesting variable: {0}", key); - //always return default - //TODO: cache settings atoms - if(!Description.Variables.ContainsKey(key)) - return false; - //HACK: return pointer for desmume mouse, i want to implement that first - if (key == "desmume_pointer_type") - { - *variables = unmanagedResources.StringToHGlobalAnsi("touch").ToPointer(); - return true; - } - *variables = unmanagedResources.StringToHGlobalAnsi(Description.Variables[key].DefaultOption).ToPointer(); - return true; - } - case LibRetro.RETRO_ENVIRONMENT.SET_VARIABLES: - { - void** variables = (void**)data.ToPointer(); - for (; ; ) - { - IntPtr pKey = new IntPtr(*variables++); - IntPtr pValue = new IntPtr(*variables++); - if(pKey == IntPtr.Zero) - break; - string key = Marshal.PtrToStringAnsi(pKey); - string value = Marshal.PtrToStringAnsi(pValue); - var vd = new VariableDescription() { Name = key}; - var parts = value.Split(';'); - vd.Description = parts[0]; - vd.Options = parts[1].TrimStart(' ').Split('|'); - Description.Variables[vd.Name] = vd; - } - } - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_VARIABLE_UPDATE: - return false; - case LibRetro.RETRO_ENVIRONMENT.SET_SUPPORT_NO_GAME: - environmentInfo.SupportNoGame = true; - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_LIBRETRO_PATH: - return false; - case LibRetro.RETRO_ENVIRONMENT.SET_AUDIO_CALLBACK: - return false; - case LibRetro.RETRO_ENVIRONMENT.SET_FRAME_TIME_CALLBACK: - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_RUMBLE_INTERFACE: - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_INPUT_DEVICE_CAPABILITIES: - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_LOG_INTERFACE: - *(IntPtr*)data = Marshal.GetFunctionPointerForDelegate(retro_log_printf_cb); - return true; - case LibRetro.RETRO_ENVIRONMENT.GET_PERF_INTERFACE: - //some builds of fmsx core crash without this set - Marshal.StructureToPtr(retro_perf_callback, data, false); - return true; - case LibRetro.RETRO_ENVIRONMENT.GET_LOCATION_INTERFACE: - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_CORE_ASSETS_DIRECTORY: - return false; - case LibRetro.RETRO_ENVIRONMENT.GET_SAVE_DIRECTORY: - //supposedly optional like everything else here, but without it ?? crashes (please write which case) - //this will suffice for now. if we find evidence later it's needed we can stash a string with - //unmanagedResources and CoreFileProvider - //mednafen NGP neopop, desmume, and others, request this, and falls back on the system directory if it isn't provided - //desmume crashes if the directory doesn't exist - Directory.CreateDirectory(SaveDirectory); - Console.WriteLine("returning save directory: " + SaveDirectory); - *((IntPtr*)data.ToPointer()) = SaveDirectoryAtom; - return true; - case LibRetro.RETRO_ENVIRONMENT.SET_CONTROLLER_INFO: - return true; - case LibRetro.RETRO_ENVIRONMENT.SET_MEMORY_MAPS: - return false; - default: - Console.WriteLine("Unknkown retro_environment command {0}", (int)cmd); - return false; - } - } - void retro_input_poll() - { - IsLagFrame = false; - } - - private bool GetButton(uint pnum, string type, string button) - { - string key = string.Format("P{0} {1} {2}", pnum, type, button); - bool b = Controller.IsPressed(key); - if (b == true) - { - return true; //debugging placeholder - } - else return false; - } - - LibRetro.retro_environment_t retro_environment_cb; - LibRetro.retro_video_refresh_t retro_video_refresh_cb; - LibRetro.retro_audio_sample_t retro_audio_sample_cb; - LibRetro.retro_audio_sample_batch_t retro_audio_sample_batch_cb; - LibRetro.retro_input_poll_t retro_input_poll_cb; - LibRetro.retro_input_state_t retro_input_state_cb; - LibRetro.retro_log_printf_t retro_log_printf_cb; - - LibRetro.retro_perf_callback retro_perf_callback = new LibRetro.retro_perf_callback(); - - #endregion - - class RetroEnvironmentInfo - { + case LibRetro.RETRO_ENVIRONMENT.GET_OVERSCAN: + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_CAN_DUPE: + //gambatte requires this + *(bool*)data.ToPointer() = true; + return true; + case LibRetro.RETRO_ENVIRONMENT.SET_MESSAGE: + { + LibRetro.retro_message msg = new LibRetro.retro_message(); + Marshal.PtrToStructure(data, msg); + if (!string.IsNullOrEmpty(msg.msg)) + Console.WriteLine("LibRetro Message: {0}", msg.msg); + return true; + } + case LibRetro.RETRO_ENVIRONMENT.SHUTDOWN: + return false; + case LibRetro.RETRO_ENVIRONMENT.SET_PERFORMANCE_LEVEL: + Console.WriteLine("Core suggested SET_PERFORMANCE_LEVEL {0}", *(uint*)data.ToPointer()); + return true; + case LibRetro.RETRO_ENVIRONMENT.GET_SYSTEM_DIRECTORY: + //mednafen NGP neopop fails to launch with no system directory + Directory.CreateDirectory(SystemDirectory); //just to be safe, it seems likely that cores will crash without a created system directory + Console.WriteLine("returning system directory: " + SystemDirectory); + *((IntPtr*)data.ToPointer()) = SystemDirectoryAtom; + return true; + case LibRetro.RETRO_ENVIRONMENT.SET_PIXEL_FORMAT: + { + LibRetro.RETRO_PIXEL_FORMAT fmt = 0; + int[] tmp = new int[1]; + Marshal.Copy(data, tmp, 0, 1); + fmt = (LibRetro.RETRO_PIXEL_FORMAT)tmp[0]; + switch (fmt) + { + case LibRetro.RETRO_PIXEL_FORMAT.RGB565: + case LibRetro.RETRO_PIXEL_FORMAT.XRGB1555: + case LibRetro.RETRO_PIXEL_FORMAT.XRGB8888: + pixelfmt = fmt; + Console.WriteLine("New pixel format set: {0}", pixelfmt); + return true; + default: + Console.WriteLine("Unrecognized pixel format: {0}", (int)pixelfmt); + return false; + } + } + case LibRetro.RETRO_ENVIRONMENT.SET_INPUT_DESCRIPTORS: + return false; + case LibRetro.RETRO_ENVIRONMENT.SET_KEYBOARD_CALLBACK: + return false; + case LibRetro.RETRO_ENVIRONMENT.SET_DISK_CONTROL_INTERFACE: + return false; + case LibRetro.RETRO_ENVIRONMENT.SET_HW_RENDER: + { + //mupen64plus needs this, as well as 3dengine + LibRetro.retro_hw_render_callback* info = (LibRetro.retro_hw_render_callback*)data.ToPointer(); + Console.WriteLine("SET_HW_RENDER: {0}, version={1}.{2}, dbg/cache={3}/{4}, depth/stencil = {5}/{6}{7}", info->context_type, info->version_minor, info->version_major, info->debug_context, info->cache_context, info->depth, info->stencil, info->bottom_left_origin ? " (bottomleft)" : ""); + return true; + } + case LibRetro.RETRO_ENVIRONMENT.GET_VARIABLE: + { + void** variables = (void**)data.ToPointer(); + IntPtr pKey = new IntPtr(*variables++); + string key = Marshal.PtrToStringAnsi(pKey); + Console.WriteLine("Requesting variable: {0}", key); + //always return default + //TODO: cache settings atoms + if(!Description.Variables.ContainsKey(key)) + return false; + //HACK: return pointer for desmume mouse, i want to implement that first + if (key == "desmume_pointer_type") + { + *variables = unmanagedResources.StringToHGlobalAnsi("touch").ToPointer(); + return true; + } + *variables = unmanagedResources.StringToHGlobalAnsi(Description.Variables[key].DefaultOption).ToPointer(); + return true; + } + case LibRetro.RETRO_ENVIRONMENT.SET_VARIABLES: + { + void** variables = (void**)data.ToPointer(); + for (; ; ) + { + IntPtr pKey = new IntPtr(*variables++); + IntPtr pValue = new IntPtr(*variables++); + if(pKey == IntPtr.Zero) + break; + string key = Marshal.PtrToStringAnsi(pKey); + string value = Marshal.PtrToStringAnsi(pValue); + var vd = new VariableDescription() { Name = key}; + var parts = value.Split(';'); + vd.Description = parts[0]; + vd.Options = parts[1].TrimStart(' ').Split('|'); + Description.Variables[vd.Name] = vd; + } + } + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_VARIABLE_UPDATE: + return false; + case LibRetro.RETRO_ENVIRONMENT.SET_SUPPORT_NO_GAME: + environmentInfo.SupportNoGame = true; + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_LIBRETRO_PATH: + return false; + case LibRetro.RETRO_ENVIRONMENT.SET_AUDIO_CALLBACK: + return false; + case LibRetro.RETRO_ENVIRONMENT.SET_FRAME_TIME_CALLBACK: + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_RUMBLE_INTERFACE: + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_INPUT_DEVICE_CAPABILITIES: + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_LOG_INTERFACE: + *(IntPtr*)data = Marshal.GetFunctionPointerForDelegate(retro_log_printf_cb); + return true; + case LibRetro.RETRO_ENVIRONMENT.GET_PERF_INTERFACE: + //some builds of fmsx core crash without this set + Marshal.StructureToPtr(retro_perf_callback, data, false); + return true; + case LibRetro.RETRO_ENVIRONMENT.GET_LOCATION_INTERFACE: + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_CORE_ASSETS_DIRECTORY: + return false; + case LibRetro.RETRO_ENVIRONMENT.GET_SAVE_DIRECTORY: + //supposedly optional like everything else here, but without it ?? crashes (please write which case) + //this will suffice for now. if we find evidence later it's needed we can stash a string with + //unmanagedResources and CoreFileProvider + //mednafen NGP neopop, desmume, and others, request this, and falls back on the system directory if it isn't provided + //desmume crashes if the directory doesn't exist + Directory.CreateDirectory(SaveDirectory); + Console.WriteLine("returning save directory: " + SaveDirectory); + *((IntPtr*)data.ToPointer()) = SaveDirectoryAtom; + return true; + case LibRetro.RETRO_ENVIRONMENT.SET_CONTROLLER_INFO: + return true; + case LibRetro.RETRO_ENVIRONMENT.SET_MEMORY_MAPS: + return false; + default: + Console.WriteLine("Unknkown retro_environment command {0}", (int)cmd); + return false; + } + } + void retro_input_poll() + { + IsLagFrame = false; + } + + private bool GetButton(uint pnum, string type, string button) + { + string key = string.Format("P{0} {1} {2}", pnum, type, button); + bool b = Controller.IsPressed(key); + if (b == true) + { + return true; //debugging placeholder + } + else return false; + } + + LibRetro.retro_environment_t retro_environment_cb; + LibRetro.retro_video_refresh_t retro_video_refresh_cb; + LibRetro.retro_audio_sample_t retro_audio_sample_cb; + LibRetro.retro_audio_sample_batch_t retro_audio_sample_batch_cb; + LibRetro.retro_input_poll_t retro_input_poll_cb; + LibRetro.retro_input_state_t retro_input_state_cb; + LibRetro.retro_log_printf_t retro_log_printf_cb; + + LibRetro.retro_perf_callback retro_perf_callback = new LibRetro.retro_perf_callback(); + + #endregion + + class RetroEnvironmentInfo + { public bool SupportNoGame; - public int Rotation_CCW; - } - - //disposable resources - private LibRetro retro; - private UnmanagedResourceHeap unmanagedResources = new UnmanagedResourceHeap(); - - /// - /// Cached information sent to the frontend by environment calls - /// - RetroEnvironmentInfo environmentInfo = new RetroEnvironmentInfo(); - - public class RetroDescription - { - /// - /// String containing a friendly display name for the core, but we probably shouldn't use this. I decided it's better to get the user used to using filenames as core 'codenames' instead. - /// - public string LibraryName; - - /// - /// String containing a friendly version number for the core library - /// - public string LibraryVersion; - - /// - /// List of extensions as "sfc|smc|fig" which this core accepts. - /// - public string ValidExtensions; - - /// - /// Whether the core needs roms to be specified as paths (can't take rom data buffersS) - /// - public bool NeedsRomAsPath; - - /// - /// Whether the core needs roms stored as archives (e.g. arcade roms). We probably shouldn't employ the dearchiver prompts when opening roms for these cores. - /// - public bool NeedsArchives; - - /// - /// Whether the core can be run without a game provided (e.g. stand-alone games, like 2048) - /// - public bool SupportsNoGame; - - /// - /// Variables defined by the core - /// - public Dictionary Variables = new Dictionary(); - } - - public class VariableDescription - { - public string Name; - public string Description; - public string[] Options; - public string DefaultOption { get { return Options[0]; } } - - public override string ToString() - { - return string.Format("{0} ({1}) = ({2})", Name, Description, string.Join("|", Options)); - } - } - - public readonly RetroDescription Description = new RetroDescription(); - - //path configuration - string SystemDirectory, SaveDirectory; - IntPtr SystemDirectoryAtom, SaveDirectoryAtom; - - public LibRetroEmulator(CoreComm nextComm, string modulename) - { - ServiceProvider = new BasicServiceProvider(this); - - _SyncSettings = new SyncSettings(); - - retro_environment_cb = new LibRetro.retro_environment_t(retro_environment); - retro_video_refresh_cb = new LibRetro.retro_video_refresh_t(retro_video_refresh); - retro_audio_sample_cb = new LibRetro.retro_audio_sample_t(retro_audio_sample); - retro_audio_sample_batch_cb = new LibRetro.retro_audio_sample_batch_t(retro_audio_sample_batch); - retro_input_poll_cb = new LibRetro.retro_input_poll_t(retro_input_poll); - retro_input_state_cb = new LibRetro.retro_input_state_t(retro_input_state); - retro_log_printf_cb = new LibRetro.retro_log_printf_t(retro_log_printf); - - //no way (need new mechanism) to check for SSSE3, MMXEXT, SSE4, SSE42 - retro_perf_callback.get_cpu_features = new LibRetro.retro_get_cpu_features_t(() => (ulong)( - (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMIAvailable) ? LibRetro.RETRO_SIMD.SSE : 0) | - (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMI64Available) ? LibRetro.RETRO_SIMD.SSE2 : 0) | - (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsSSE3Available) ? LibRetro.RETRO_SIMD.SSE3 : 0) | - (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsMMXAvailable) ? LibRetro.RETRO_SIMD.MMX : 0) - ) ); - retro_perf_callback.get_perf_counter = new LibRetro.retro_perf_get_counter_t(() => System.Diagnostics.Stopwatch.GetTimestamp()); - retro_perf_callback.get_time_usec = new LibRetro.retro_perf_get_time_usec_t(() => DateTime.Now.Ticks / 10); - retro_perf_callback.perf_log = new LibRetro.retro_perf_log_t( () => {} ); - retro_perf_callback.perf_register = new LibRetro.retro_perf_register_t((ref LibRetro.retro_perf_counter counter) => { }); - retro_perf_callback.perf_start = new LibRetro.retro_perf_start_t((ref LibRetro.retro_perf_counter counter) => { }); - retro_perf_callback.perf_stop = new LibRetro.retro_perf_stop_t((ref LibRetro.retro_perf_counter counter) => { }); - - retro = new LibRetro(modulename); - - try - { - CoreComm = nextComm; - - //this series of steps may be mystical. - LibRetro.retro_system_info system_info = new LibRetro.retro_system_info(); - retro.retro_get_system_info(ref system_info); - - //the dosbox core calls GET_SYSTEM_DIRECTORY and GET_SAVE_DIRECTORY from retro_set_environment. - //so, lets set some temporary values (which we'll replace) - SystemDirectory = Path.GetDirectoryName(modulename); - SystemDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SystemDirectory); - SaveDirectory = Path.GetDirectoryName(modulename); - SaveDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SaveDirectory); - retro.retro_set_environment(retro_environment_cb); - - retro.retro_set_video_refresh(retro_video_refresh_cb); - retro.retro_set_audio_sample(retro_audio_sample_cb); - retro.retro_set_audio_sample_batch(retro_audio_sample_batch_cb); - retro.retro_set_input_poll(retro_input_poll_cb); - retro.retro_set_input_state(retro_input_state_cb); - - //compile descriptive information - Description.NeedsArchives = system_info.block_extract; - Description.NeedsRomAsPath = system_info.need_fullpath; - Description.LibraryName = system_info.library_name; - Description.LibraryVersion = system_info.library_version; - Description.ValidExtensions = system_info.valid_extensions; - Description.SupportsNoGame = environmentInfo.SupportNoGame; - } - catch - { - retro.Dispose(); - retro = null; - throw; - } - - - } - - public IEmulatorServiceProvider ServiceProvider { get; private set; } - - - - public bool LoadData(byte[] data) - { - LibRetro.retro_game_info gi = new LibRetro.retro_game_info(); - fixed (byte* p = &data[0]) - { - gi.data = (IntPtr)p; - gi.meta = ""; - gi.path = ""; - gi.size = (uint)data.Length; - return LoadWork(ref gi); - } - } - - public bool LoadPath(string path) - { - LibRetro.retro_game_info gi = new LibRetro.retro_game_info(); - gi.path = path; //is this the right encoding? seems to be ok - return LoadWork(ref gi); - } - - public bool LoadNoGame() - { - LibRetro.retro_game_info gi = new LibRetro.retro_game_info(); - return LoadWork(ref gi); - } - - bool LoadWork(ref LibRetro.retro_game_info gi) - { - //defer this until loading because during the LibRetroEmulator constructor, we dont have access to the game name and so paths can't be selected - //this cannot be done until set_environment is complete - if (CoreComm.CoreFileProvider == null) - { - SaveDirectory = SystemDirectory = ""; - } - else - { - SystemDirectory = CoreComm.CoreFileProvider.GetRetroSystemPath(); - SaveDirectory = CoreComm.CoreFileProvider.GetRetroSaveRAMDirectory(); - SystemDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SystemDirectory); - SaveDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SaveDirectory); - } - - //defer this until loading because it triggers the core to read save and system paths - //if any cores did that from set_environment then i'm assured we can call set_environment again here before retro_init and it should work - //--alcaro says any cores that can't handle that should be considered a bug - //UPDATE: dosbox does that, so lets try it - retro.retro_set_environment(retro_environment_cb); - retro.retro_init(); - - if (!retro.retro_load_game(ref gi)) - { - Console.WriteLine("retro_load_game() failed"); - return false; - } - - //TODO - libretro cores can return a varying serialize size over time. I tried to get them to write it in the docs... - savebuff = new byte[retro.retro_serialize_size()]; - savebuff2 = new byte[savebuff.Length + 13]; - - LibRetro.retro_system_av_info av = new LibRetro.retro_system_av_info(); - retro.retro_get_system_av_info(ref av); - - BufferWidth = (int)av.geometry.base_width; - BufferHeight = (int)av.geometry.base_height; - vidbuff = new int[av.geometry.max_width * av.geometry.max_height]; - dar = av.geometry.aspect_ratio; - - // TODO: more precise - CoreComm.VsyncNum = (int)(10000000 * av.timing.fps); - CoreComm.VsyncDen = 10000000; - - SetupResampler(av.timing.fps, av.timing.sample_rate); - (ServiceProvider as BasicServiceProvider).Register(resampler); - - ControllerDefinition = CreateControllerDefinition(_SyncSettings); - - return true; - } - - public static ControllerDefinition CreateControllerDefinition(SyncSettings syncSettings) - { - ControllerDefinition definition = new ControllerDefinition(); - definition.Name = "LibRetro Controls"; // <-- for compatibility - - foreach(var item in new[] { - "P1 {0} Up", "P1 {0} Down", "P1 {0} Left", "P1 {0} Right", "P1 {0} Select", "P1 {0} Start", "P1 {0} Y", "P1 {0} B", "P1 {0} X", "P1 {0} A", "P1 {0} L", "P1 {0} R", - "P2 {0} Up", "P2 {0} Down", "P2 {0} Left", "P2 {0} Right", "P2 {0} Select", "P2 {0} Start", "P2 {0} Y", "P2 {0} B", "P2 {0} X", "P2 {0} A", "P2 {0} L", "P2 {0} R", - }) - definition.BoolButtons.Add(string.Format(item,"RetroPad")); - - definition.BoolButtons.Add("Pointer Pressed"); //TODO: this isnt showing up in the binding panel. I dont want to find out why. - definition.FloatControls.Add("Pointer X"); - definition.FloatControls.Add("Pointer Y"); - definition.FloatRanges.Add(new ControllerDefinition.FloatRange(-32767, 0, 32767)); - definition.FloatRanges.Add(new ControllerDefinition.FloatRange(-32767, 0, 32767)); - - foreach (var key in new[]{ - "Key Backspace", "Key Tab", "Key Clear", "Key Return", "Key Pause", "Key Escape", - "Key Space", "Key Exclaim", "Key QuoteDbl", "Key Hash", "Key Dollar", "Key Ampersand", "Key Quote", "Key LeftParen", "Key RightParen", "Key Asterisk", "Key Plus", "Key Comma", "Key Minus", "Key Period", "Key Slash", - "Key 0", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", - "Key Colon", "Key Semicolon", "Key Less", "Key Equals", "Key Greater", "Key Question", "Key At", "Key LeftBracket", "Key Backslash", "Key RightBracket", "Key Caret", "Key Underscore", "Key Backquote", - "Key A", "Key B", "Key C", "Key D", "Key E", "Key F", "Key G", "Key H", "Key I", "Key J", "Key K", "Key L", "Key M", "Key N", "Key O", "Key P", "Key Q", "Key R", "Key S", "Key T", "Key U", "Key V", "Key W", "Key X", "Key Y", "Key Z", - "Key Delete", - "Key KP0", "Key KP1", "Key KP2", "Key KP3", "Key KP4", "Key KP5", "Key KP6", "Key KP7", "Key KP8", "Key KP9", - "Key KP_Period", "Key KP_Divide", "Key KP_Multiply", "Key KP_Minus", "Key KP_Plus", "Key KP_Enter", "Key KP_Equals", - "Key Up", "Key Down", "Key Right", "Key Left", "Key Insert", "Key Home", "Key End", "Key PageUp", "Key PageDown", - "Key F1", "Key F2", "Key F3", "Key F4", "Key F5", "Key F6", "Key F7", "Key F8", "Key F9", "Key F10", "Key F11", "Key F12", "Key F13", "Key F14", "Key F15", - "Key NumLock", "Key CapsLock", "Key ScrollLock", "Key RShift", "Key LShift", "Key RCtrl", "Key LCtrl", "Key RAlt", "Key LAlt", "Key RMeta", "Key LMeta", "Key LSuper", "Key RSuper", "Key Mode", "Key Compose", - "Key Help", "Key Print", "Key SysReq", "Key Break", "Key Menu", "Key Power", "Key Euro", "Key Undo" - }) - { - definition.BoolButtons.Add(key); - definition.CategoryLabels[key] = "RetroKeyboard"; - } - - return definition; - } - - public ControllerDefinition ControllerDefinition { get; private set; } - public IController Controller { get; set; } - - public void FrameAdvance(bool render, bool rendersound = true) - { - //TODO - consider changing directory and using Libretro subdir of bizhawk as a kind of sandbox, for the duration of the run? - IsLagFrame = true; - Frame++; - nsamprecv = 0; - retro.retro_run(); - //Console.WriteLine("[{0}]", nsamprecv); - } - - public int Frame { get; private set; } - - public string SystemId - { - get { return "Libretro"; } - } - - public bool DeterministicEmulation - { - // who knows - get { return true; } - } - - public string BoardName - { - get { return null; } - } - - #region ISaveRam - //TODO - terrible things will happen if this changes at runtime - - byte[] saverambuff = new byte[0]; - - public byte[] CloneSaveRam() - { - int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM); - if (saverambuff.Length != size) - saverambuff = new byte[size]; - - IntPtr src = retro.retro_get_memory_data(LibRetro.RETRO_MEMORY.SAVE_RAM); - if (src == IntPtr.Zero) - return null; - - Marshal.Copy(src, saverambuff, 0, size); - return (byte[])saverambuff.Clone(); - } - - public void StoreSaveRam(byte[] data) - { - int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM); - - if (size == 0) - return; - - IntPtr dst = retro.retro_get_memory_data(LibRetro.RETRO_MEMORY.SAVE_RAM); - if (dst == IntPtr.Zero) - throw new Exception("retro_get_memory_data(RETRO_MEMORY_SAVE_RAM) returned NULL"); - - Marshal.Copy(data, 0, dst, size); - } - - public bool SaveRamModified - { - [FeatureNotImplemented] - get - { - //if we dont have saveram, it isnt modified. otherwise, assume it is - int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM); - if (size == 0) - return false; - return true; - } - - [FeatureNotImplemented] - set { throw new NotImplementedException(); } - } - - #endregion - - public void ResetCounters() - { - Frame = 0; - LagCount = 0; - IsLagFrame = false; - } - - #region savestates - - private byte[] savebuff; - private byte[] savebuff2; - - public void SaveStateText(System.IO.TextWriter writer) - { - var temp = SaveStateBinary(); - temp.SaveAsHex(writer); - } - - public void LoadStateText(System.IO.TextReader reader) - { - string hex = reader.ReadLine(); - byte[] state = new byte[hex.Length / 2]; - state.ReadFromHex(hex); - LoadStateBinary(new BinaryReader(new MemoryStream(state))); - } - - public void SaveStateBinary(System.IO.BinaryWriter writer) - { - //is this the only way we know of to detect unavailable savestates? - if (savebuff.Length > 0) - { - fixed (byte* ptr = &savebuff[0]) - { - if (!retro.retro_serialize((IntPtr)ptr, (uint)savebuff.Length)) - throw new Exception("retro_serialize() failed"); - } - } - - writer.Write(savebuff.Length); - writer.Write(savebuff); - // other variables - writer.Write(Frame); - writer.Write(LagCount); - writer.Write(IsLagFrame); - } - - public void LoadStateBinary(System.IO.BinaryReader reader) - { - int newlen = reader.ReadInt32(); - if (newlen > savebuff.Length) - throw new Exception("Unexpected buffer size"); - reader.Read(savebuff, 0, newlen); - if (savebuff.Length > 0) - { - fixed (byte* ptr = &savebuff[0]) - { - if (!retro.retro_unserialize((IntPtr)ptr, (uint)newlen)) - throw new Exception("retro_unserialize() failed"); - } - } - // other variables - Frame = reader.ReadInt32(); - LagCount = reader.ReadInt32(); - IsLagFrame = reader.ReadBoolean(); - } - - public byte[] SaveStateBinary() - { - var ms = new System.IO.MemoryStream(savebuff2, true); - var bw = new System.IO.BinaryWriter(ms); - SaveStateBinary(bw); - bw.Flush(); - ms.Close(); - return savebuff2; - } - - public bool BinarySaveStatesPreferred { get { return true; } } - - #endregion - - public CoreComm CoreComm - { - get; - private set; - } - - #region memory access - - void SetupDebuggingStuff() - { - } - - public MemoryDomainList MemoryDomains { get; private set; } - - #endregion - - public void Dispose() - { - if (resampler != null) - { - resampler.Dispose(); - resampler = null; - } - if (retro != null) - { - retro.Dispose(); - retro = null; - } - unmanagedResources.Dispose(); - unmanagedResources = null; - } - - #region ISoundProvider - - SpeexResampler resampler; - - short[] sampbuff = new short[0]; - - // debug - int nsamprecv = 0; - - void SetupResampler(double fps, double sps) - { - Console.WriteLine("FPS {0} SPS {1}", fps, sps); - - // todo: more precise? - uint spsnum = (uint)sps * 1000; - uint spsden = (uint)1000; - - resampler = new SpeexResampler(5, 44100 * spsden, spsnum, (uint)sps, 44100, null, null); - } - - void retro_audio_sample(short left, short right) - { - resampler.EnqueueSample(left, right); - nsamprecv++; - } - - uint retro_audio_sample_batch(IntPtr data, uint frames) - { - if (sampbuff.Length < frames * 2) - sampbuff = new short[frames * 2]; - Marshal.Copy(data, sampbuff, 0, (int)(frames * 2)); - resampler.EnqueueSamples(sampbuff, (int)frames); - nsamprecv += (int)frames; - // what is the return from this used for? - return frames; - } - - #endregion - - #region IVideoProvider - - float dar; - int[] vidbuff, rawvidbuff; - LibRetro.RETRO_PIXEL_FORMAT pixelfmt = LibRetro.RETRO_PIXEL_FORMAT.XRGB1555; - - void Blit555(short* src, int* dst, int width, int height, int pitch) - { - for (int j = 0; j < height; j++) - { - short* row = src; - for (int i = 0; i < width; i++) - { - short ci = *row; - int r = ci & 0x001f; - int g = ci & 0x03e0; - int b = ci & 0x7c00; - - r = (r << 3) | (r >> 2); - g = (g >> 2) | (g >> 7); - b = (b >> 7) | (b >> 12); - int co = r | g | b | unchecked((int)0xff000000); - - *dst = co; - dst++; - row++; - } - src += pitch; - } - } - - void Blit565(short* src, int* dst, int width, int height, int pitch) - { - for (int j = 0; j < height; j++) - { - short* row = src; - for (int i = 0; i < width; i++) - { - short ci = *row; - int r = ci & 0x001f; - int g = (ci & 0x07e0)>>5; - int b = (ci & 0xf800)>>11; - - r = (r << 3) | (r >> 2); - g = (g << 2) | (g >> 4); - b = (b << 3) | (b >> 2); - int co = (b<<16) | (g<<8) | r; - - *dst = co; - dst++; - row++; - } - src += pitch; - } - } - - void Blit888(int* src, int* dst, int width, int height, int pitch) - { - for (int j = 0; j < height; j++) - { - int* row = src; - for (int i = 0; i < width; i++) - { - int ci = *row; - int co = ci | unchecked((int)0xff000000); - *dst = co; - dst++; - row++; - } - src += pitch; - } - } - - void retro_video_refresh(IntPtr data, uint width, uint height, uint pitch) - { - if (data == IntPtr.Zero) // dup frame + public int Rotation_CCW; + } + + //disposable resources + private LibRetro retro; + private UnmanagedResourceHeap unmanagedResources = new UnmanagedResourceHeap(); + + /// + /// Cached information sent to the frontend by environment calls + /// + RetroEnvironmentInfo environmentInfo = new RetroEnvironmentInfo(); + + public class RetroDescription + { + /// + /// String containing a friendly display name for the core, but we probably shouldn't use this. I decided it's better to get the user used to using filenames as core 'codenames' instead. + /// + public string LibraryName; + + /// + /// String containing a friendly version number for the core library + /// + public string LibraryVersion; + + /// + /// List of extensions as "sfc|smc|fig" which this core accepts. + /// + public string ValidExtensions; + + /// + /// Whether the core needs roms to be specified as paths (can't take rom data buffersS) + /// + public bool NeedsRomAsPath; + + /// + /// Whether the core needs roms stored as archives (e.g. arcade roms). We probably shouldn't employ the dearchiver prompts when opening roms for these cores. + /// + public bool NeedsArchives; + + /// + /// Whether the core can be run without a game provided (e.g. stand-alone games, like 2048) + /// + public bool SupportsNoGame; + + /// + /// Variables defined by the core + /// + public Dictionary Variables = new Dictionary(); + } + + public class VariableDescription + { + public string Name; + public string Description; + public string[] Options; + public string DefaultOption { get { return Options[0]; } } + + public override string ToString() + { + return string.Format("{0} ({1}) = ({2})", Name, Description, string.Join("|", Options)); + } + } + + public readonly RetroDescription Description = new RetroDescription(); + + //path configuration + string SystemDirectory, SaveDirectory; + IntPtr SystemDirectoryAtom, SaveDirectoryAtom; + + public LibRetroEmulator(CoreComm nextComm, string modulename) + { + ServiceProvider = new BasicServiceProvider(this); + + _SyncSettings = new SyncSettings(); + + retro_environment_cb = new LibRetro.retro_environment_t(retro_environment); + retro_video_refresh_cb = new LibRetro.retro_video_refresh_t(retro_video_refresh); + retro_audio_sample_cb = new LibRetro.retro_audio_sample_t(retro_audio_sample); + retro_audio_sample_batch_cb = new LibRetro.retro_audio_sample_batch_t(retro_audio_sample_batch); + retro_input_poll_cb = new LibRetro.retro_input_poll_t(retro_input_poll); + retro_input_state_cb = new LibRetro.retro_input_state_t(retro_input_state); + retro_log_printf_cb = new LibRetro.retro_log_printf_t(retro_log_printf); + + //no way (need new mechanism) to check for SSSE3, MMXEXT, SSE4, SSE42 + retro_perf_callback.get_cpu_features = new LibRetro.retro_get_cpu_features_t(() => (ulong)( + (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMIAvailable) ? LibRetro.RETRO_SIMD.SSE : 0) | + (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMI64Available) ? LibRetro.RETRO_SIMD.SSE2 : 0) | + (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsSSE3Available) ? LibRetro.RETRO_SIMD.SSE3 : 0) | + (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsMMXAvailable) ? LibRetro.RETRO_SIMD.MMX : 0) + ) ); + retro_perf_callback.get_perf_counter = new LibRetro.retro_perf_get_counter_t(() => System.Diagnostics.Stopwatch.GetTimestamp()); + retro_perf_callback.get_time_usec = new LibRetro.retro_perf_get_time_usec_t(() => DateTime.Now.Ticks / 10); + retro_perf_callback.perf_log = new LibRetro.retro_perf_log_t( () => {} ); + retro_perf_callback.perf_register = new LibRetro.retro_perf_register_t((ref LibRetro.retro_perf_counter counter) => { }); + retro_perf_callback.perf_start = new LibRetro.retro_perf_start_t((ref LibRetro.retro_perf_counter counter) => { }); + retro_perf_callback.perf_stop = new LibRetro.retro_perf_stop_t((ref LibRetro.retro_perf_counter counter) => { }); + + retro = new LibRetro(modulename); + + try + { + CoreComm = nextComm; + + //this series of steps may be mystical. + LibRetro.retro_system_info system_info = new LibRetro.retro_system_info(); + retro.retro_get_system_info(ref system_info); + + //the dosbox core calls GET_SYSTEM_DIRECTORY and GET_SAVE_DIRECTORY from retro_set_environment. + //so, lets set some temporary values (which we'll replace) + SystemDirectory = Path.GetDirectoryName(modulename); + SystemDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SystemDirectory); + SaveDirectory = Path.GetDirectoryName(modulename); + SaveDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SaveDirectory); + retro.retro_set_environment(retro_environment_cb); + + retro.retro_set_video_refresh(retro_video_refresh_cb); + retro.retro_set_audio_sample(retro_audio_sample_cb); + retro.retro_set_audio_sample_batch(retro_audio_sample_batch_cb); + retro.retro_set_input_poll(retro_input_poll_cb); + retro.retro_set_input_state(retro_input_state_cb); + + //compile descriptive information + Description.NeedsArchives = system_info.block_extract; + Description.NeedsRomAsPath = system_info.need_fullpath; + Description.LibraryName = system_info.library_name; + Description.LibraryVersion = system_info.library_version; + Description.ValidExtensions = system_info.valid_extensions; + Description.SupportsNoGame = environmentInfo.SupportNoGame; + } + catch + { + retro.Dispose(); + retro = null; + throw; + } + + + } + + public IEmulatorServiceProvider ServiceProvider { get; private set; } + + + + public bool LoadData(byte[] data) + { + LibRetro.retro_game_info gi = new LibRetro.retro_game_info(); + fixed (byte* p = &data[0]) + { + gi.data = (IntPtr)p; + gi.meta = ""; + gi.path = ""; + gi.size = (uint)data.Length; + return LoadWork(ref gi); + } + } + + public bool LoadPath(string path) + { + LibRetro.retro_game_info gi = new LibRetro.retro_game_info(); + gi.path = path; //is this the right encoding? seems to be ok + return LoadWork(ref gi); + } + + public bool LoadNoGame() + { + LibRetro.retro_game_info gi = new LibRetro.retro_game_info(); + return LoadWork(ref gi); + } + + bool LoadWork(ref LibRetro.retro_game_info gi) + { + //defer this until loading because during the LibRetroEmulator constructor, we dont have access to the game name and so paths can't be selected + //this cannot be done until set_environment is complete + if (CoreComm.CoreFileProvider == null) + { + SaveDirectory = SystemDirectory = ""; + } + else + { + SystemDirectory = CoreComm.CoreFileProvider.GetRetroSystemPath(); + SaveDirectory = CoreComm.CoreFileProvider.GetRetroSaveRAMDirectory(); + SystemDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SystemDirectory); + SaveDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SaveDirectory); + } + + //defer this until loading because it triggers the core to read save and system paths + //if any cores did that from set_environment then i'm assured we can call set_environment again here before retro_init and it should work + //--alcaro says any cores that can't handle that should be considered a bug + //UPDATE: dosbox does that, so lets try it + retro.retro_set_environment(retro_environment_cb); + retro.retro_init(); + + if (!retro.retro_load_game(ref gi)) + { + Console.WriteLine("retro_load_game() failed"); + return false; + } + + //TODO - libretro cores can return a varying serialize size over time. I tried to get them to write it in the docs... + savebuff = new byte[retro.retro_serialize_size()]; + savebuff2 = new byte[savebuff.Length + 13]; + + LibRetro.retro_system_av_info av = new LibRetro.retro_system_av_info(); + retro.retro_get_system_av_info(ref av); + + BufferWidth = (int)av.geometry.base_width; + BufferHeight = (int)av.geometry.base_height; + vidbuff = new int[av.geometry.max_width * av.geometry.max_height]; + dar = av.geometry.aspect_ratio; + + // TODO: more precise + CoreComm.VsyncNum = (int)(10000000 * av.timing.fps); + CoreComm.VsyncDen = 10000000; + + SetupResampler(av.timing.fps, av.timing.sample_rate); + (ServiceProvider as BasicServiceProvider).Register(resampler); + + ControllerDefinition = CreateControllerDefinition(_SyncSettings); + + return true; + } + + public static ControllerDefinition CreateControllerDefinition(SyncSettings syncSettings) + { + ControllerDefinition definition = new ControllerDefinition(); + definition.Name = "LibRetro Controls"; // <-- for compatibility + + foreach(var item in new[] { + "P1 {0} Up", "P1 {0} Down", "P1 {0} Left", "P1 {0} Right", "P1 {0} Select", "P1 {0} Start", "P1 {0} Y", "P1 {0} B", "P1 {0} X", "P1 {0} A", "P1 {0} L", "P1 {0} R", + "P2 {0} Up", "P2 {0} Down", "P2 {0} Left", "P2 {0} Right", "P2 {0} Select", "P2 {0} Start", "P2 {0} Y", "P2 {0} B", "P2 {0} X", "P2 {0} A", "P2 {0} L", "P2 {0} R", + }) + definition.BoolButtons.Add(string.Format(item,"RetroPad")); + + definition.BoolButtons.Add("Pointer Pressed"); //TODO: this isnt showing up in the binding panel. I dont want to find out why. + definition.FloatControls.Add("Pointer X"); + definition.FloatControls.Add("Pointer Y"); + definition.FloatRanges.Add(new ControllerDefinition.FloatRange(-32767, 0, 32767)); + definition.FloatRanges.Add(new ControllerDefinition.FloatRange(-32767, 0, 32767)); + + foreach (var key in new[]{ + "Key Backspace", "Key Tab", "Key Clear", "Key Return", "Key Pause", "Key Escape", + "Key Space", "Key Exclaim", "Key QuoteDbl", "Key Hash", "Key Dollar", "Key Ampersand", "Key Quote", "Key LeftParen", "Key RightParen", "Key Asterisk", "Key Plus", "Key Comma", "Key Minus", "Key Period", "Key Slash", + "Key 0", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", + "Key Colon", "Key Semicolon", "Key Less", "Key Equals", "Key Greater", "Key Question", "Key At", "Key LeftBracket", "Key Backslash", "Key RightBracket", "Key Caret", "Key Underscore", "Key Backquote", + "Key A", "Key B", "Key C", "Key D", "Key E", "Key F", "Key G", "Key H", "Key I", "Key J", "Key K", "Key L", "Key M", "Key N", "Key O", "Key P", "Key Q", "Key R", "Key S", "Key T", "Key U", "Key V", "Key W", "Key X", "Key Y", "Key Z", + "Key Delete", + "Key KP0", "Key KP1", "Key KP2", "Key KP3", "Key KP4", "Key KP5", "Key KP6", "Key KP7", "Key KP8", "Key KP9", + "Key KP_Period", "Key KP_Divide", "Key KP_Multiply", "Key KP_Minus", "Key KP_Plus", "Key KP_Enter", "Key KP_Equals", + "Key Up", "Key Down", "Key Right", "Key Left", "Key Insert", "Key Home", "Key End", "Key PageUp", "Key PageDown", + "Key F1", "Key F2", "Key F3", "Key F4", "Key F5", "Key F6", "Key F7", "Key F8", "Key F9", "Key F10", "Key F11", "Key F12", "Key F13", "Key F14", "Key F15", + "Key NumLock", "Key CapsLock", "Key ScrollLock", "Key RShift", "Key LShift", "Key RCtrl", "Key LCtrl", "Key RAlt", "Key LAlt", "Key RMeta", "Key LMeta", "Key LSuper", "Key RSuper", "Key Mode", "Key Compose", + "Key Help", "Key Print", "Key SysReq", "Key Break", "Key Menu", "Key Power", "Key Euro", "Key Undo" + }) + { + definition.BoolButtons.Add(key); + definition.CategoryLabels[key] = "RetroKeyboard"; + } + + return definition; + } + + public ControllerDefinition ControllerDefinition { get; private set; } + public IController Controller { get; set; } + + public void FrameAdvance(bool render, bool rendersound = true) + { + //TODO - consider changing directory and using Libretro subdir of bizhawk as a kind of sandbox, for the duration of the run? + IsLagFrame = true; + Frame++; + nsamprecv = 0; + retro.retro_run(); + //Console.WriteLine("[{0}]", nsamprecv); + } + + public int Frame { get; private set; } + + public string SystemId + { + get { return "Libretro"; } + } + + public bool DeterministicEmulation + { + // who knows + get { return true; } + } + + public string BoardName + { + get { return null; } + } + + #region ISaveRam + //TODO - terrible things will happen if this changes at runtime + + byte[] saverambuff = new byte[0]; + + public byte[] CloneSaveRam() + { + int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM); + if (saverambuff.Length != size) + saverambuff = new byte[size]; + + IntPtr src = retro.retro_get_memory_data(LibRetro.RETRO_MEMORY.SAVE_RAM); + if (src == IntPtr.Zero) + return null; + + Marshal.Copy(src, saverambuff, 0, size); + return (byte[])saverambuff.Clone(); + } + + public void StoreSaveRam(byte[] data) + { + int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM); + + if (size == 0) + return; + + IntPtr dst = retro.retro_get_memory_data(LibRetro.RETRO_MEMORY.SAVE_RAM); + if (dst == IntPtr.Zero) + throw new Exception("retro_get_memory_data(RETRO_MEMORY_SAVE_RAM) returned NULL"); + + Marshal.Copy(data, 0, dst, size); + } + + public bool SaveRamModified + { + [FeatureNotImplemented] + get + { + //if we dont have saveram, it isnt modified. otherwise, assume it is + int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM); + if (size == 0) + return false; + return true; + } + + [FeatureNotImplemented] + set { throw new NotImplementedException(); } + } + + #endregion + + public void ResetCounters() + { + Frame = 0; + LagCount = 0; + IsLagFrame = false; + } + + #region savestates + + private byte[] savebuff; + private byte[] savebuff2; + + public void SaveStateText(System.IO.TextWriter writer) + { + var temp = SaveStateBinary(); + temp.SaveAsHex(writer); + } + + public void LoadStateText(System.IO.TextReader reader) + { + string hex = reader.ReadLine(); + byte[] state = new byte[hex.Length / 2]; + state.ReadFromHex(hex); + LoadStateBinary(new BinaryReader(new MemoryStream(state))); + } + + public void SaveStateBinary(System.IO.BinaryWriter writer) + { + //is this the only way we know of to detect unavailable savestates? + if (savebuff.Length > 0) + { + fixed (byte* ptr = &savebuff[0]) + { + if (!retro.retro_serialize((IntPtr)ptr, (uint)savebuff.Length)) + throw new Exception("retro_serialize() failed"); + } + } + + writer.Write(savebuff.Length); + writer.Write(savebuff); + // other variables + writer.Write(Frame); + writer.Write(LagCount); + writer.Write(IsLagFrame); + } + + public void LoadStateBinary(System.IO.BinaryReader reader) + { + int newlen = reader.ReadInt32(); + if (newlen > savebuff.Length) + throw new Exception("Unexpected buffer size"); + reader.Read(savebuff, 0, newlen); + if (savebuff.Length > 0) + { + fixed (byte* ptr = &savebuff[0]) + { + if (!retro.retro_unserialize((IntPtr)ptr, (uint)newlen)) + throw new Exception("retro_unserialize() failed"); + } + } + // other variables + Frame = reader.ReadInt32(); + LagCount = reader.ReadInt32(); + IsLagFrame = reader.ReadBoolean(); + } + + public byte[] SaveStateBinary() + { + var ms = new System.IO.MemoryStream(savebuff2, true); + var bw = new System.IO.BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + ms.Close(); + return savebuff2; + } + + public bool BinarySaveStatesPreferred { get { return true; } } + + #endregion + + public CoreComm CoreComm + { + get; + private set; + } + + #region memory access + + void SetupDebuggingStuff() + { + } + + public MemoryDomainList MemoryDomains { get; private set; } + + #endregion + + public void Dispose() + { + if (resampler != null) + { + resampler.Dispose(); + resampler = null; + } + if (retro != null) + { + retro.Dispose(); + retro = null; + } + unmanagedResources.Dispose(); + unmanagedResources = null; + } + + #region ISoundProvider + + SpeexResampler resampler; + + short[] sampbuff = new short[0]; + + // debug + int nsamprecv = 0; + + void SetupResampler(double fps, double sps) + { + Console.WriteLine("FPS {0} SPS {1}", fps, sps); + + // todo: more precise? + uint spsnum = (uint)sps * 1000; + uint spsden = (uint)1000; + + resampler = new SpeexResampler(5, 44100 * spsden, spsnum, (uint)sps, 44100, null, null); + } + + void retro_audio_sample(short left, short right) + { + resampler.EnqueueSample(left, right); + nsamprecv++; + } + + uint retro_audio_sample_batch(IntPtr data, uint frames) + { + if (sampbuff.Length < frames * 2) + sampbuff = new short[frames * 2]; + Marshal.Copy(data, sampbuff, 0, (int)(frames * 2)); + resampler.EnqueueSamples(sampbuff, (int)frames); + nsamprecv += (int)frames; + // what is the return from this used for? + return frames; + } + + #endregion + + #region IVideoProvider + + float dar; + int[] vidbuff, rawvidbuff; + LibRetro.RETRO_PIXEL_FORMAT pixelfmt = LibRetro.RETRO_PIXEL_FORMAT.XRGB1555; + + void Blit555(short* src, int* dst, int width, int height, int pitch) + { + for (int j = 0; j < height; j++) + { + short* row = src; + for (int i = 0; i < width; i++) + { + short ci = *row; + int r = ci & 0x001f; + int g = ci & 0x03e0; + int b = ci & 0x7c00; + + r = (r << 3) | (r >> 2); + g = (g >> 2) | (g >> 7); + b = (b >> 7) | (b >> 12); + int co = r | g | b | unchecked((int)0xff000000); + + *dst = co; + dst++; + row++; + } + src += pitch; + } + } + + void Blit565(short* src, int* dst, int width, int height, int pitch) + { + for (int j = 0; j < height; j++) + { + short* row = src; + for (int i = 0; i < width; i++) + { + short ci = *row; + int r = ci & 0x001f; + int g = (ci & 0x07e0)>>5; + int b = (ci & 0xf800)>>11; + + r = (r << 3) | (r >> 2); + g = (g << 2) | (g >> 4); + b = (b << 3) | (b >> 2); + int co = (b<<16) | (g<<8) | r; + + *dst = co; + dst++; + row++; + } + src += pitch; + } + } + + void Blit888(int* src, int* dst, int width, int height, int pitch) + { + for (int j = 0; j < height; j++) + { + int* row = src; + for (int i = 0; i < width; i++) + { + int ci = *row; + int co = ci | unchecked((int)0xff000000); + *dst = co; + dst++; + row++; + } + src += pitch; + } + } + + void retro_video_refresh(IntPtr data, uint width, uint height, uint pitch) + { + if (data == IntPtr.Zero) // dup frame return; //if (BufferWidth != width) BufferWidth = (int)width; //if (BufferHeight != height) BufferHeight = (int)height; //if (BufferWidth * BufferHeight != rawvidbuff.Length) - // rawvidbuff = new int[BufferWidth * BufferHeight]; - - //if we have rotation, we might have a geometry mismatch and in any event we need a temp buffer to do the rotation from + // rawvidbuff = new int[BufferWidth * BufferHeight]; + + //if we have rotation, we might have a geometry mismatch and in any event we need a temp buffer to do the rotation from //but that's a general problem, isnt it? if (rawvidbuff == null || rawvidbuff.Length != width * height) { @@ -868,17 +868,17 @@ namespace BizHawk.Emulation.Cores int[] target = vidbuff; if (environmentInfo.Rotation_CCW != 0) - target = rawvidbuff; - - - fixed (int* dst = &target[0]) - { - if (pixelfmt == LibRetro.RETRO_PIXEL_FORMAT.XRGB8888) - Blit888((int*)data, dst, (int)width, (int)height, (int)pitch / 4); - else if (pixelfmt == LibRetro.RETRO_PIXEL_FORMAT.RGB565) - Blit565((short*)data, dst, (int)width, (int)height, (int)pitch / 2); - else - Blit555((short*)data, dst, (int)width, (int)height, (int)pitch / 2); + target = rawvidbuff; + + + fixed (int* dst = &target[0]) + { + if (pixelfmt == LibRetro.RETRO_PIXEL_FORMAT.XRGB8888) + Blit888((int*)data, dst, (int)width, (int)height, (int)pitch / 4); + else if (pixelfmt == LibRetro.RETRO_PIXEL_FORMAT.RGB565) + Blit565((short*)data, dst, (int)width, (int)height, (int)pitch / 2); + else + Blit555((short*)data, dst, (int)width, (int)height, (int)pitch / 2); } int dw = BufferWidth, dh = BufferHeight; @@ -900,55 +900,55 @@ namespace BizHawk.Emulation.Cores else if (environmentInfo.Rotation_CCW == 180) { throw new InvalidOperationException("PLEASE REPORT THIS BUG: STAPH REGULARIZATION PROTOCOL"); - } - } - - - public int[] GetVideoBuffer() - { - return vidbuff; - } - - public int VirtualWidth - { - get - { - if(dar<=0) - return BufferWidth; - else if (dar > 1.0f) - return (int)(BufferHeight * dar); - else - return BufferWidth; - } - } - public int VirtualHeight - { - get - { - if(dar<=0) - return BufferHeight; - if (dar < 1.0f) - return (int)(BufferWidth / dar); - else - return BufferHeight; - } - } - - public int BufferWidth { get; private set; } - public int BufferHeight { get; private set; } - public int BackgroundColor { get { return unchecked((int)0xff000000); } } - - #endregion - - #region IInputPollable - public int LagCount { get; set; } - public bool IsLagFrame { get; set; } - public IInputCallbackSystem InputCallbacks - { - [FeatureNotImplemented] - get - { throw new NotImplementedException(); } - } - #endregion - } -} + } + } + + + public int[] GetVideoBuffer() + { + return vidbuff; + } + + public int VirtualWidth + { + get + { + if(dar<=0) + return BufferWidth; + else if (dar > 1.0f) + return (int)(BufferHeight * dar); + else + return BufferWidth; + } + } + public int VirtualHeight + { + get + { + if(dar<=0) + return BufferHeight; + if (dar < 1.0f) + return (int)(BufferWidth / dar); + else + return BufferHeight; + } + } + + public int BufferWidth { get; private set; } + public int BufferHeight { get; private set; } + public int BackgroundColor { get { return unchecked((int)0xff000000); } } + + #endregion + + #region IInputPollable + public int LagCount { get; set; } + public bool IsLagFrame { get; set; } + public IInputCallbackSystem InputCallbacks + { + [FeatureNotImplemented] + get + { throw new NotImplementedException(); } + } + #endregion + } +} diff --git a/Bizware/BizHawk.Bizware.BizwareGL/CGC.cs b/Bizware/BizHawk.Bizware.BizwareGL/CGC.cs index cce73cc286..572ed175f8 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL/CGC.cs +++ b/Bizware/BizHawk.Bizware.BizwareGL/CGC.cs @@ -1,114 +1,114 @@ using System; using System.IO; -using System.Threading; -using System.Diagnostics; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; - -//todo - be able to run out of PATH too - -namespace BizHawk.Bizware.BizwareGL -{ - public class CGC - { - public CGC() - { - } - - public static string CGCBinPath; - - private static string[] Escape(IEnumerable args) - { - return args.Select(s => s.Contains(" ") ? string.Format("\"{0}\"", s) : s).ToArray(); - } - - public class Results - { - public bool Succeeded; - public string Code, Errors; - public Dictionary MapCodeToNative = new Dictionary(); - public Dictionary MapNativeToCode = new Dictionary(); +using System.Threading; +using System.Diagnostics; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +//todo - be able to run out of PATH too + +namespace BizHawk.Bizware.BizwareGL +{ + public class CGC + { + public CGC() + { } - Regex rxHlslSamplerCrashWorkaround = new Regex(@"\((.*?)(in sampler2D)(.*?)\)", RegexOptions.Multiline | RegexOptions.IgnoreCase); - - public Results Run(string code, string entry, string profile, bool hlslHacks) - { - //version=110; GLSL generates old fashioned semantic attributes and not generic attributes - string[] args = new[]{"-profile", profile, "-entry", entry, "-po", "version=110"}; - - args = Escape(args); - StringBuilder sbCmdline = new StringBuilder(); - for (int i = 0; i < args.Length; i++) - { - sbCmdline.Append(args[i]); - if (i != args.Length - 1) sbCmdline.Append(' '); - } - - //http://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why - using (Process proc = new Process()) - { - proc.StartInfo.UseShellExecute = false; - proc.StartInfo.CreateNoWindow = true; - proc.StartInfo.RedirectStandardInput = true; - proc.StartInfo.RedirectStandardOutput = true; - proc.StartInfo.RedirectStandardError = true; - proc.StartInfo.Arguments = sbCmdline.ToString(); - proc.StartInfo.FileName = CGCBinPath; - - StringBuilder output = new StringBuilder(), error = new StringBuilder(); - - using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) - using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) - { - proc.OutputDataReceived += (sender, e) => - { - if (e.Data == null) outputWaitHandle.Set(); - else output.AppendLine(e.Data); - }; - proc.ErrorDataReceived += (sender, e) => - { - if (e.Data == null) errorWaitHandle.Set(); - else error.AppendLine(e.Data); - }; - - - proc.Start(); - new Thread(() => - { - proc.StandardInput.AutoFlush = true; - proc.StandardInput.Write(code); - proc.StandardInput.Flush(); - proc.StandardInput.Close(); - }).Start(); - - proc.BeginOutputReadLine(); - proc.BeginErrorReadLine(); - proc.WaitForExit(); - outputWaitHandle.WaitOne(); - errorWaitHandle.WaitOne(); - } - - bool ok = (proc.ExitCode == 0); - - var ret = new Results() - { - Succeeded = ok, - Code = output.ToString(), - Errors = error.ToString() + public static string CGCBinPath; + + private static string[] Escape(IEnumerable args) + { + return args.Select(s => s.Contains(" ") ? string.Format("\"{0}\"", s) : s).ToArray(); + } + + public class Results + { + public bool Succeeded; + public string Code, Errors; + public Dictionary MapCodeToNative = new Dictionary(); + public Dictionary MapNativeToCode = new Dictionary(); + } + + Regex rxHlslSamplerCrashWorkaround = new Regex(@"\((.*?)(in sampler2D)(.*?)\)", RegexOptions.Multiline | RegexOptions.IgnoreCase); + + public Results Run(string code, string entry, string profile, bool hlslHacks) + { + //version=110; GLSL generates old fashioned semantic attributes and not generic attributes + string[] args = new[]{"-profile", profile, "-entry", entry, "-po", "version=110"}; + + args = Escape(args); + StringBuilder sbCmdline = new StringBuilder(); + for (int i = 0; i < args.Length; i++) + { + sbCmdline.Append(args[i]); + if (i != args.Length - 1) sbCmdline.Append(' '); + } + + //http://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why + using (Process proc = new Process()) + { + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.CreateNoWindow = true; + proc.StartInfo.RedirectStandardInput = true; + proc.StartInfo.RedirectStandardOutput = true; + proc.StartInfo.RedirectStandardError = true; + proc.StartInfo.Arguments = sbCmdline.ToString(); + proc.StartInfo.FileName = CGCBinPath; + + StringBuilder output = new StringBuilder(), error = new StringBuilder(); + + using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) + using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) + { + proc.OutputDataReceived += (sender, e) => + { + if (e.Data == null) outputWaitHandle.Set(); + else output.AppendLine(e.Data); + }; + proc.ErrorDataReceived += (sender, e) => + { + if (e.Data == null) errorWaitHandle.Set(); + else error.AppendLine(e.Data); + }; + + + proc.Start(); + new Thread(() => + { + proc.StandardInput.AutoFlush = true; + proc.StandardInput.Write(code); + proc.StandardInput.Flush(); + proc.StandardInput.Close(); + }).Start(); + + proc.BeginOutputReadLine(); + proc.BeginErrorReadLine(); + proc.WaitForExit(); + outputWaitHandle.WaitOne(); + errorWaitHandle.WaitOne(); + } + + bool ok = (proc.ExitCode == 0); + + var ret = new Results() + { + Succeeded = ok, + Code = output.ToString(), + Errors = error.ToString() }; if (!ok) - Console.WriteLine(ret.Errors); - + Console.WriteLine(ret.Errors); + if (hlslHacks) { ret.Code = rxHlslSamplerCrashWorkaround.Replace(ret.Code, m => string.Format("({0}uniform sampler2D{1})", m.Groups[1].Value, m.Groups[3].Value)); - } - - //make variable name map + } + + //make variable name map //loop until the first line that doesnt start with a comment var reader = new StringReader(ret.Code); for(;;) @@ -131,10 +131,10 @@ namespace BizHawk.Bizware.BizwareGL ret.MapCodeToNative[code_name] = native_name; ret.MapNativeToCode[native_name] = code_name; } - } - - return ret; - } - } - } -} + } + + return ret; + } + } + } +} diff --git a/Bizware/BizHawk.Bizware.BizwareGL/RetroShader.cs b/Bizware/BizHawk.Bizware.BizwareGL/RetroShader.cs index d6707a1d5e..5ee54a167f 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL/RetroShader.cs +++ b/Bizware/BizHawk.Bizware.BizwareGL/RetroShader.cs @@ -1,46 +1,46 @@ -using System; -using System.Drawing; -using System.Windows.Forms; - -using OpenTK; -using OpenTK.Graphics.OpenGL; - -namespace BizHawk.Bizware.BizwareGL -{ - /// - /// Handles RetroArch's GLSL shader pass format - /// - public class RetroShader : IDisposable +using System; +using System.Drawing; +using System.Windows.Forms; + +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace BizHawk.Bizware.BizwareGL +{ + /// + /// Handles RetroArch's GLSL shader pass format + /// + public class RetroShader : IDisposable { //NOTE: we may need to overhaul uniform-setting infrastructure later. - //maybe samplers will need to be set by index and not by name (I think the specs dont dictate what the sampler must be named) - - public RetroShader(IGL owner, string source, bool debug = false) - { - Owner = owner; - + //maybe samplers will need to be set by index and not by name (I think the specs dont dictate what the sampler must be named) + + public RetroShader(IGL owner, string source, bool debug = false) + { + Owner = owner; + VertexLayout = owner.CreateVertexLayout(); VertexLayout.DefineVertexAttribute("position", 0, 4, VertexAttribPointerType.Float, AttributeUsage.Position, false, 40, 0); VertexLayout.DefineVertexAttribute("color", 1, 4, VertexAttribPointerType.Float, AttributeUsage.Color0, false, 40, 16); //just dead weight, i have no idea why this is here. but some old HLSL compilers (used in bizhawk for various reasons) will want it to exist here since it exists in the vertex shader VertexLayout.DefineVertexAttribute("texCoord1", 2, 2, VertexAttribPointerType.Float, AttributeUsage.Texcoord0, false, 40, 32); - VertexLayout.Close(); - - string defines = "#define TEXCOORD TEXCOORD0\r\n"; //maybe not safe.. - string vsSource = "#define VERTEX\r\n" + defines + source; - string psSource = "#define FRAGMENT\r\n" + defines + source; - var vs = owner.CreateVertexShader(true, vsSource, "main_vertex", debug); - var ps = owner.CreateFragmentShader(true, psSource, "main_fragment", debug); + VertexLayout.Close(); + + string defines = "#define TEXCOORD TEXCOORD0\r\n"; //maybe not safe.. + string vsSource = "#define VERTEX\r\n" + defines + source; + string psSource = "#define FRAGMENT\r\n" + defines + source; + var vs = owner.CreateVertexShader(true, vsSource, "main_vertex", debug); + var ps = owner.CreateFragmentShader(true, psSource, "main_fragment", debug); Pipeline = Owner.CreatePipeline(VertexLayout, vs, ps, debug, "retro"); if (!Pipeline.Available) { Available = false; return; - } - - //retroarch shaders will sometimes not have the right sampler name - //it's unclear whether we should bind to s_p or sampler0 - //lets bind to sampler0 in case we dont have s_p + } + + //retroarch shaders will sometimes not have the right sampler name + //it's unclear whether we should bind to s_p or sampler0 + //lets bind to sampler0 in case we dont have s_p sampler0 = Pipeline.TryGetUniform("s_p"); if (sampler0 == null) { @@ -58,80 +58,80 @@ namespace BizHawk.Bizware.BizwareGL if (sampler0 == null) return; - Available = true; + Available = true; } public bool Available { get; private set; } public string Errors { get { return Pipeline.Errors; } } - PipelineUniform sampler0; - - public void Dispose() - { - Pipeline.Dispose(); - } - - public void Bind() - { - //lame... - Owner.BindPipeline(Pipeline); - } - - public unsafe void Run(Texture2d tex, Size InputSize, Size OutputSize, bool flip) - { - flip = false; - //test - - //ack! make sure to set the pipeline before setting uniforms - Bind(); - + PipelineUniform sampler0; + + public void Dispose() + { + Pipeline.Dispose(); + } + + public void Bind() + { + //lame... + Owner.BindPipeline(Pipeline); + } + + public unsafe void Run(Texture2d tex, Size InputSize, Size OutputSize, bool flip) + { + flip = false; + //test + + //ack! make sure to set the pipeline before setting uniforms + Bind(); + Pipeline["IN.video_size"].Set(new Vector2(InputSize.Width, InputSize.Height)); - Pipeline["IN.texture_size"].Set(new Vector2(tex.Width, tex.Height)); - Pipeline["IN.output_size"].Set(new Vector2(OutputSize.Width, OutputSize.Height)); - Pipeline["IN.frame_count"].Set(1); //todo - Pipeline["IN.frame_direction"].Set(1); //todo - - - var Projection = Owner.CreateGuiProjectionMatrix(OutputSize); + Pipeline["IN.texture_size"].Set(new Vector2(tex.Width, tex.Height)); + Pipeline["IN.output_size"].Set(new Vector2(OutputSize.Width, OutputSize.Height)); + Pipeline["IN.frame_count"].Set(1); //todo + Pipeline["IN.frame_direction"].Set(1); //todo + + + var Projection = Owner.CreateGuiProjectionMatrix(OutputSize); var Modelview = Owner.CreateGuiViewMatrix(OutputSize); var mat = Modelview * Projection; mat.Transpose(); - Pipeline["modelViewProj"].Set(mat, true); - + Pipeline["modelViewProj"].Set(mat, true); + Owner.SetTextureWrapMode(tex, true); - sampler0.Set(tex); - Owner.SetViewport(OutputSize); - + sampler0.Set(tex); + Owner.SetViewport(OutputSize); + int w = OutputSize.Width; - int h = OutputSize.Height; - float v0,v1; - if (flip) { v0 = 1; v1 = 0; } - else { v0 = 0; v1 = 1; } - float* pData = stackalloc float[10*4]; - int i=0; + int h = OutputSize.Height; + float v0,v1; + if (flip) { v0 = 1; v1 = 0; } + else { v0 = 0; v1 = 1; } + float* pData = stackalloc float[10*4]; + int i=0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 1; //topleft vert pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; //useless color - pData[i++] = 0; pData[i++] = v0; + pData[i++] = 0; pData[i++] = v0; pData[i++] = w; pData[i++] = 0; pData[i++] = 0; pData[i++] = 1; //topright vert pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; //useless color - pData[i++] = 1; pData[i++] = v0; + pData[i++] = 1; pData[i++] = v0; pData[i++] = 0; pData[i++] = h; pData[i++] = 0; pData[i++] = 1; //bottomleft vert pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; //useless color - pData[i++] = 0; pData[i++] = v1; + pData[i++] = 0; pData[i++] = v1; pData[i++] = w; pData[i++] = h; pData[i++] = 0; pData[i++] = 1; //bottomright vert pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; //useless color - pData[i++] = 1; pData[i++] = v1; - - Owner.SetBlendState(Owner.BlendNoneCopy); - Owner.BindArrayData(pData); - Owner.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); - } - - - public IGL Owner { get; private set; } - - VertexLayout VertexLayout; - public Pipeline Pipeline; - } + pData[i++] = 1; pData[i++] = v1; + + Owner.SetBlendState(Owner.BlendNoneCopy); + Owner.BindArrayData(pData); + Owner.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); + } + + + public IGL Owner { get; private set; } + + VertexLayout VertexLayout; + public Pipeline Pipeline; + } } \ No newline at end of file