2011-02-20 08:40:22 +00:00
using System ;
2014-04-14 16:48:45 +00:00
using System.Collections.Generic ;
2015-01-31 22:16:02 +00:00
using System.Diagnostics ;
2011-01-11 02:55:51 +00:00
using System.Drawing ;
using System.Drawing.Imaging ;
using System.IO ;
2013-07-16 01:59:59 +00:00
using System.Linq ;
using System.Text ;
using System.Threading ;
2011-01-11 02:55:51 +00:00
using System.Windows.Forms ;
2014-05-31 14:29:27 +00:00
2013-12-20 22:05:56 +00:00
using BizHawk.Common ;
2014-07-03 19:20:34 +00:00
using BizHawk.Common.BufferExtensions ;
2014-07-03 18:29:51 +00:00
using BizHawk.Common.IOExtensions ;
2014-07-03 19:20:34 +00:00
using BizHawk.Client.Common ;
2014-06-02 20:16:59 +00:00
using BizHawk.Bizware.BizwareGL ;
2014-07-03 19:20:34 +00:00
2013-11-04 01:06:36 +00:00
using BizHawk.Emulation.Common ;
2014-05-31 14:29:27 +00:00
using BizHawk.Emulation.Common.IEmulatorExtensions ;
2014-04-20 16:19:08 +00:00
using BizHawk.Emulation.Cores.Atari.Atari2600 ;
2013-12-20 22:05:56 +00:00
using BizHawk.Emulation.Cores.Calculators ;
2014-04-25 01:19:57 +00:00
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES ;
2014-04-13 22:08:46 +00:00
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx ;
2013-11-13 23:36:21 +00:00
using BizHawk.Emulation.Cores.Nintendo.Gameboy ;
using BizHawk.Emulation.Cores.Nintendo.GBA ;
2013-12-20 22:05:56 +00:00
using BizHawk.Emulation.Cores.Nintendo.NES ;
using BizHawk.Emulation.Cores.Nintendo.SNES ;
using BizHawk.Emulation.Cores.PCEngine ;
2014-04-13 19:44:08 +00:00
using BizHawk.Emulation.Cores.Sega.MasterSystem ;
2013-12-20 22:05:56 +00:00
using BizHawk.Emulation.DiscSystem ;
2014-05-17 20:02:10 +00:00
using BizHawk.Emulation.Cores.Nintendo.N64 ;
2013-10-25 00:57:23 +00:00
2014-07-27 15:22:30 +00:00
using BizHawk.Client.EmuHawk.WinFormExtensions ;
2014-07-28 01:51:11 +00:00
using BizHawk.Client.EmuHawk.ToolExtensions ;
2014-07-29 01:11:57 +00:00
using BizHawk.Client.EmuHawk.CoreExtensions ;
2016-05-29 14:50:16 +00:00
using BizHawk.Client.ApiHawk ;
2016-12-12 03:37:28 +00:00
using BizHawk.Emulation.Common.Base_Implementations ;
2014-07-27 15:22:30 +00:00
2013-11-03 03:54:37 +00:00
namespace BizHawk.Client.EmuHawk
2011-01-11 02:55:51 +00:00
{
2011-02-20 08:40:22 +00:00
public partial class MainForm : Form
{
2013-11-03 02:51:21 +00:00
#region Constructors and Initialization , and Tear down
2013-10-25 00:57:23 +00:00
2013-11-03 02:51:21 +00:00
private void MainForm_Load ( object sender , EventArgs e )
2013-10-25 00:57:23 +00:00
{
2014-07-21 20:34:53 +00:00
SetWindowText ( ) ;
2013-10-25 00:57:23 +00:00
2014-02-17 09:20:08 +00:00
// Hide Status bar icons and general statusbar prep
2015-01-04 15:04:44 +00:00
MainStatusBar . Padding = new Padding ( MainStatusBar . Padding . Left , MainStatusBar . Padding . Top , MainStatusBar . Padding . Left , MainStatusBar . Padding . Bottom ) ; // Workaround to remove extra padding on right
2013-11-03 02:51:21 +00:00
PlayRecordStatusButton . Visible = false ;
AVIStatusLabel . Visible = false ;
SetPauseStatusbarIcon ( ) ;
2016-01-31 01:24:30 +00:00
ToolFormBase . UpdateCheatRelatedTools ( null , null ) ;
2013-11-03 02:51:21 +00:00
RebootStatusBarIcon . Visible = false ;
2015-01-04 15:04:44 +00:00
UpdateNotification . Visible = false ;
2014-02-17 09:20:08 +00:00
StatusBarDiskLightOnImage = Properties . Resources . LightOn ;
StatusBarDiskLightOffImage = Properties . Resources . LightOff ;
2014-08-23 01:18:59 +00:00
LinkCableOn = Properties . Resources . connect_16x16 ;
LinkCableOff = Properties . Resources . noconnect_16x16 ;
2014-06-19 01:50:16 +00:00
UpdateCoreStatusBarButton ( ) ;
2014-07-03 23:08:27 +00:00
if ( Global . Config . FirstBoot = = true )
{
ProfileFirstBootLabel . Visible = true ;
}
2014-08-23 01:18:59 +00:00
HandleToggleLightAndLink ( ) ;
2015-06-06 22:31:56 +00:00
SetStatusBar ( ) ;
2015-01-04 15:04:44 +00:00
// New version notification
UpdateChecker . CheckComplete + = ( s2 , e2 ) = >
{
if ( IsDisposed ) return ;
2015-01-04 18:22:17 +00:00
this . BeginInvoke ( ( ) = > { UpdateNotification . Visible = UpdateChecker . IsNewVersionAvailable ; } ) ;
2015-01-04 15:04:44 +00:00
} ;
UpdateChecker . BeginCheck ( ) ; // Won't actually check unless enabled by user
2013-10-06 16:40:51 +00:00
}
2013-08-25 04:23:27 +00:00
2013-01-02 18:52:11 +00:00
static MainForm ( )
{
2013-12-20 22:05:56 +00:00
// If this isnt here, then our assemblyresolving hacks wont work due to the check for MainForm.INTERIM
// its.. weird. dont ask.
2013-01-02 18:52:11 +00:00
}
2012-07-23 00:33:30 +00:00
2014-06-08 23:30:34 +00:00
CoreComm CreateCoreComm ( )
{
CoreComm ret = new CoreComm ( ShowMessageCoreComm , NotifyCoreComm ) ;
2016-02-21 23:19:20 +00:00
ret . ReleaseGLContext = ( o ) = > GlobalWin . GLManager . ReleaseGLContext ( o ) ;
ret . RequestGLContext = ( major , minor , forward ) = > GlobalWin . GLManager . CreateGLContext ( major , minor , forward ) ;
2014-06-08 23:30:34 +00:00
ret . ActivateGLContext = ( gl ) = > GlobalWin . GLManager . Activate ( ( GLManager . ContextRef ) gl ) ;
ret . DeactivateGLContext = ( ) = > GlobalWin . GLManager . Deactivate ( ) ;
return ret ;
}
2011-02-20 08:40:22 +00:00
public MainForm ( string [ ] args )
{
2013-11-03 16:07:58 +00:00
GlobalWin . MainForm = this ;
2014-05-04 14:10:28 +00:00
Global . Rewinder = new Rewinder
2013-12-27 01:14:17 +00:00
{
MessageCallback = GlobalWin . OSD . AddMessage
} ;
2013-12-24 21:37:51 +00:00
Global . ControllerInputCoalescer = new ControllerInputCoalescer ( ) ;
2013-11-01 23:17:30 +00:00
Global . FirmwareManager = new FirmwareManager ( ) ;
2013-11-01 18:52:26 +00:00
Global . MovieSession = new MovieSession
{
2014-06-12 21:45:47 +00:00
Movie = MovieService . DefaultInstance ,
2014-06-19 01:47:22 +00:00
MovieControllerAdapter = MovieService . DefaultInstance . LogGeneratorInstance ( ) . MovieControllerAdapter ,
2013-11-03 16:07:58 +00:00
MessageCallback = GlobalWin . OSD . AddMessage ,
2014-07-14 00:35:33 +00:00
AskYesNoCallback = StateErrorAskUser ,
PauseCallback = PauseEmulator ,
ModeChangedCallback = SetMainformMovieInfo
2013-11-01 18:52:26 +00:00
} ;
2013-12-27 16:23:12 +00:00
2013-12-29 23:35:42 +00:00
new AutoResetEvent ( false ) ;
2013-04-16 00:19:31 +00:00
Icon = Properties . Resources . logo ;
2011-03-21 00:54:30 +00:00
InitializeComponent ( ) ;
2014-07-21 22:21:52 +00:00
Global . Game = GameInfo . NullInstance ;
2011-07-10 20:01:27 +00:00
if ( Global . Config . ShowLogWindow )
{
2014-05-06 01:27:56 +00:00
LogConsole . ShowConsole ( ) ;
2013-10-27 07:54:00 +00:00
DisplayLogWindowMenuItem . Checked = true ;
2011-07-10 20:01:27 +00:00
}
2011-09-24 16:19:38 +00:00
2013-11-27 23:35:32 +00:00
_throttle = new Throttle ( ) ;
2011-08-27 18:09:54 +00:00
2013-11-16 16:30:20 +00:00
Global . CheatList = new CheatCollection ( ) ;
2016-01-31 01:24:30 +00:00
Global . CheatList . Changed + = ToolFormBase . UpdateCheatRelatedTools ;
2014-01-01 03:03:10 +00:00
2011-07-22 01:14:13 +00:00
UpdateStatusSlots ( ) ;
2012-12-02 16:17:42 +00:00
UpdateKeyPriorityIcon ( ) ;
2011-08-09 00:51:46 +00:00
2013-12-20 22:05:56 +00:00
// In order to allow late construction of this database, we hook up a delegate here to dearchive the data and provide it on demand
// we could background thread this later instead if we wanted to be real clever
2011-06-11 12:54:26 +00:00
NES . BootGodDB . GetDatabaseBytes = ( ) = >
{
2016-11-13 00:18:19 +00:00
string xmlPath = Path . Combine ( PathManager . GetExeDirectoryAbsolute ( ) , "gamedb" , "NesCarts.xml" ) ;
string x7zPath = Path . Combine ( PathManager . GetExeDirectoryAbsolute ( ) , "gamedb" , "NesCarts.7z" ) ;
bool loadXml = File . Exists ( xmlPath ) ;
using ( var NesCartFile = new HawkFile ( loadXml ? xmlPath : x7zPath ) )
2013-12-20 22:05:56 +00:00
{
2016-11-13 00:18:19 +00:00
if ( ! loadXml ) { NesCartFile . BindFirst ( ) ; }
2014-07-03 18:29:51 +00:00
return NesCartFile
. GetStream ( )
. ReadAllBytes ( ) ;
2013-12-20 22:05:56 +00:00
}
2011-03-07 10:41:46 +00:00
} ;
2013-10-25 00:57:23 +00:00
2014-12-16 19:22:49 +00:00
// TODO - replace this with some kind of standard dictionary-yielding parser in a separate component
string cmdRom = null ;
string cmdLoadState = null ;
2015-10-18 02:36:04 +00:00
string cmdLoadSlot = null ;
2014-12-16 19:22:49 +00:00
string cmdMovie = null ;
string cmdDumpType = null ;
string cmdDumpName = null ;
bool startFullscreen = false ;
for ( int i = 0 ; i < args . Length ; i + + )
{
// For some reason sometimes visual studio will pass this to us on the commandline. it makes no sense.
if ( args [ i ] = = ">" )
{
i + + ;
var stdout = args [ i ] ;
Console . SetOut ( new StreamWriter ( stdout ) ) ;
continue ;
}
var arg = args [ i ] . ToLower ( ) ;
if ( arg . StartsWith ( "--load-slot=" ) )
2015-10-18 02:36:04 +00:00
{
cmdLoadSlot = arg . Substring ( arg . IndexOf ( '=' ) + 1 ) ;
}
if ( arg . StartsWith ( "--load-state=" ) )
2014-12-16 19:22:49 +00:00
{
cmdLoadState = arg . Substring ( arg . IndexOf ( '=' ) + 1 ) ;
}
else if ( arg . StartsWith ( "--movie=" ) )
{
cmdMovie = arg . Substring ( arg . IndexOf ( '=' ) + 1 ) ;
}
else if ( arg . StartsWith ( "--dump-type=" ) )
{
cmdDumpType = arg . Substring ( arg . IndexOf ( '=' ) + 1 ) ;
}
2015-01-27 04:05:20 +00:00
else if ( arg . StartsWith ( "--dump-frames=" ) )
{
var list = arg . Substring ( arg . IndexOf ( '=' ) + 1 ) ;
var items = list . Split ( ',' ) ;
_currAviWriterFrameList = new HashSet < int > ( ) ;
for ( int j = 0 ; j < items . Length ; j + + )
_currAviWriterFrameList . Add ( int . Parse ( items [ j ] ) ) ;
//automatically set dump length to maximum frame
_autoDumpLength = _currAviWriterFrameList . OrderBy ( x = > x ) . Last ( ) ;
}
2014-12-16 19:22:49 +00:00
else if ( arg . StartsWith ( "--dump-name=" ) )
{
cmdDumpName = arg . Substring ( arg . IndexOf ( '=' ) + 1 ) ;
}
else if ( arg . StartsWith ( "--dump-length=" ) )
{
int . TryParse ( arg . Substring ( arg . IndexOf ( '=' ) + 1 ) , out _autoDumpLength ) ;
}
else if ( arg . StartsWith ( "--dump-close" ) )
{
_autoCloseOnDump = true ;
}
else if ( arg . StartsWith ( "--chromeless" ) )
{
_chromeless = true ;
}
else if ( arg . StartsWith ( "--fullscreen" ) )
{
startFullscreen = true ;
}
else
{
cmdRom = arg ;
}
}
2012-10-09 01:54:15 +00:00
Database . LoadDatabase ( Path . Combine ( PathManager . GetExeDirectoryAbsolute ( ) , "gamedb" , "gamedb.txt" ) ) ;
2011-01-11 02:55:51 +00:00
2014-01-27 00:02:21 +00:00
//TODO GL - a lot of disorganized wiring-up here
2015-08-20 23:35:53 +00:00
CGC . CGCBinPath = Path . Combine ( PathManager . GetDllDirectory ( ) , "cgc.exe" ) ;
2015-02-22 03:53:07 +00:00
PresentationPanel = new PresentationPanel ( ) ;
2016-03-27 09:49:17 +00:00
PresentationPanel . GraphicsControl . MainWindow = true ;
2015-02-22 03:53:07 +00:00
GlobalWin . DisplayManager = new DisplayManager ( PresentationPanel ) ;
Controls . Add ( PresentationPanel ) ;
Controls . SetChildIndex ( PresentationPanel , 0 ) ;
2011-01-11 02:55:51 +00:00
2014-01-27 00:02:21 +00:00
//TODO GL - move these event handlers somewhere less obnoxious line in the On* overrides
2011-02-20 08:40:22 +00:00
Load + = ( o , e ) = >
2011-02-21 16:35:42 +00:00
{
AllowDrop = true ;
DragEnter + = FormDragEnter ;
DragDrop + = FormDragDrop ;
} ;
2011-02-20 08:40:22 +00:00
2011-06-11 12:54:26 +00:00
Closing + = ( o , e ) = >
{
2013-11-05 16:37:05 +00:00
if ( GlobalWin . Tools . AskSave ( ) )
{
2015-11-04 03:50:32 +00:00
//zero 03-nov-2015 - close game after other steps. tools might need to unhook themselves from a core.
2013-11-05 16:37:05 +00:00
Global . MovieSession . Movie . Stop ( ) ;
GlobalWin . Tools . Close ( ) ;
2015-11-04 03:50:32 +00:00
CloseGame ( ) ;
//does this need to be last for any particular reason? do tool dialogs persist settings when closing?
2013-11-05 16:37:05 +00:00
SaveConfig ( ) ;
}
else
{
e . Cancel = true ;
}
2011-06-11 12:54:26 +00:00
} ;
2011-02-20 08:40:22 +00:00
ResizeBegin + = ( o , e ) = >
{
2014-09-14 00:51:30 +00:00
_inResizeLoop = true ;
2013-12-20 22:05:56 +00:00
if ( GlobalWin . Sound ! = null )
{
GlobalWin . Sound . StopSound ( ) ;
}
2011-02-20 08:40:22 +00:00
} ;
2014-09-14 00:51:30 +00:00
Resize + = ( o , e ) = >
{
SetWindowText ( ) ;
} ;
2011-02-20 08:40:22 +00:00
ResizeEnd + = ( o , e ) = >
{
2014-09-14 00:51:30 +00:00
_inResizeLoop = false ;
2014-11-18 18:33:04 +00:00
SetWindowText ( ) ;
2015-02-22 03:53:07 +00:00
if ( PresentationPanel ! = null )
2013-12-20 22:05:56 +00:00
{
2015-02-22 03:53:07 +00:00
PresentationPanel . Resized = true ;
2013-12-20 22:05:56 +00:00
}
if ( GlobalWin . Sound ! = null )
{
GlobalWin . Sound . StartSound ( ) ;
}
2011-02-20 08:40:22 +00:00
} ;
2011-07-13 01:29:13 +00:00
Input . Initialize ( ) ;
InitControls ( ) ;
2015-02-22 20:06:30 +00:00
var comm = CreateCoreComm ( ) ;
CoreFileProvider . SyncCoreCommInputSignals ( comm ) ;
2016-12-04 17:19:34 +00:00
Emulator = new NullEmulator ( comm , Global . Config . GetCoreSettings < NullEmulator > ( ) ) ;
2015-02-22 20:38:10 +00:00
Global . ActiveController = new Controller ( NullEmulator . NullController ) ;
2013-10-27 16:26:37 +00:00
Global . AutoFireController = Global . AutofireNullControls ;
2013-11-03 16:47:21 +00:00
Global . AutofireStickyXORAdapter . SetOnOffPatternFromConfig ( ) ;
2015-01-31 04:49:53 +00:00
try { GlobalWin . Sound = new Sound ( Handle ) ; }
catch
{
2015-01-31 06:40:14 +00:00
string message = "Couldn't initialize sound device! Try changing the output method in Sound config." ;
if ( Global . Config . SoundOutputMethod = = Config . ESoundOutputMethod . DirectSound )
message = "Couldn't initialize DirectSound! Things may go poorly for you. Try changing your sound driver to 44.1khz instead of 48khz in mmsys.cpl." ;
MessageBox . Show ( message , "Initialization Error" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
Global . Config . SoundOutputMethod = Config . ESoundOutputMethod . Dummy ;
GlobalWin . Sound = new Sound ( Handle ) ;
2015-01-31 04:49:53 +00:00
}
2013-11-03 16:07:58 +00:00
GlobalWin . Sound . StartSound ( ) ;
2013-12-24 21:59:41 +00:00
InputManager . RewireInputChain ( ) ;
2015-02-22 04:02:30 +00:00
GlobalWin . Tools = new ToolManager ( this ) ;
2013-12-18 19:36:17 +00:00
RewireSound ( ) ;
2013-12-20 22:05:56 +00:00
2014-11-09 16:00:39 +00:00
// Workaround for windows, location is -32000 when minimized, if they close it during this time, that's what gets saved
if ( Global . Config . MainWndx = = - 32000 )
{
Global . Config . MainWndx = 0 ;
}
if ( Global . Config . MainWndy = = - 32000 )
{
Global . Config . MainWndy = 0 ;
}
if ( Global . Config . MainWndx ! = - 1 & & Global . Config . MainWndy ! = - 1 & & Global . Config . SaveWindowPosition )
2013-12-12 21:05:09 +00:00
{
Location = new Point ( Global . Config . MainWndx , Global . Config . MainWndy ) ;
}
2011-03-19 09:12:56 +00:00
if ( cmdRom ! = null )
{
2013-12-20 22:05:56 +00:00
// Commandline should always override auto-load
2015-11-12 23:47:39 +00:00
LoadRom ( cmdRom , new MainForm . LoadRomArgs ( ) { OpenAdvanced = new OpenAdvanced_OpenRom ( ) } ) ;
2011-03-19 09:12:56 +00:00
if ( Global . Game = = null )
{
2011-05-22 00:13:12 +00:00
MessageBox . Show ( "Failed to load " + cmdRom + " specified on commandline" ) ;
2011-03-19 09:12:56 +00:00
}
}
2013-09-07 03:15:29 +00:00
else if ( Global . Config . RecentRoms . AutoLoad & & ! Global . Config . RecentRoms . Empty )
{
2014-04-06 20:46:23 +00:00
LoadRomFromRecent ( Global . Config . RecentRoms . MostRecent ) ;
2013-09-07 03:15:29 +00:00
}
2011-01-19 04:18:33 +00:00
2011-06-11 12:54:26 +00:00
if ( cmdMovie ! = null )
{
2015-08-01 15:13:22 +00:00
_supressSyncSettingsWarning = true ; // We dont' want to be nagged if we are attempting to automate
2011-06-30 02:30:06 +00:00
if ( Global . Game = = null )
2012-09-03 19:42:53 +00:00
{
2013-11-27 23:35:32 +00:00
OpenRom ( ) ;
2012-09-03 19:42:53 +00:00
}
2015-08-01 14:55:19 +00:00
// If user picked a game, then do the commandline logic
if ( ! Global . Game . IsNullInstance )
2011-06-30 02:30:06 +00:00
{
2014-06-11 21:14:13 +00:00
var movie = MovieService . Get ( cmdMovie ) ;
2013-12-03 18:08:45 +00:00
Global . MovieSession . ReadOnly = true ;
2013-12-20 22:05:56 +00:00
2012-07-23 00:33:30 +00:00
// if user is dumping and didnt supply dump length, make it as long as the loaded movie
2013-11-27 23:35:32 +00:00
if ( _autoDumpLength = = 0 )
2012-09-03 19:42:53 +00:00
{
2013-11-30 03:10:05 +00:00
_autoDumpLength = movie . InputLogLength ;
2012-09-03 19:42:53 +00:00
}
2013-12-20 22:05:56 +00:00
2015-08-01 14:55:19 +00:00
// Copy pasta from drag & drop
string errorMsg ;
string warningMsg ;
if ( MovieImport . IsValidMovieExtension ( Path . GetExtension ( cmdMovie ) ) )
{
var imported = MovieImport . ImportFile ( cmdMovie , 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 ( imported , false ) ;
}
GlobalWin . OSD . AddMessage ( warningMsg ) ;
}
else
{
StartNewMovie ( movie , false ) ;
Global . Config . RecentMovies . Add ( cmdMovie ) ;
}
2015-08-01 15:13:22 +00:00
_supressSyncSettingsWarning = false ;
2011-06-30 02:30:06 +00:00
}
2011-06-11 12:54:26 +00:00
}
2013-09-07 03:15:29 +00:00
else if ( Global . Config . RecentMovies . AutoLoad & & ! Global . Config . RecentMovies . Empty )
2011-06-11 12:54:26 +00:00
{
2014-09-27 15:01:39 +00:00
if ( Global . Game . IsNullInstance )
2012-09-03 19:42:53 +00:00
{
2013-11-27 23:35:32 +00:00
OpenRom ( ) ;
2012-09-03 19:42:53 +00:00
}
2014-09-27 15:01:39 +00:00
// If user picked a game, then do the autoload logic
if ( ! Global . Game . IsNullInstance )
2011-06-30 02:30:06 +00:00
{
2014-09-27 15:01:39 +00:00
if ( File . Exists ( Global . Config . RecentMovies . MostRecent ) )
{
StartNewMovie ( MovieService . Get ( Global . Config . RecentMovies . MostRecent ) , false ) ;
}
else
{
Global . Config . RecentMovies . HandleLoadError ( Global . Config . RecentMovies . MostRecent ) ;
}
2011-06-30 02:30:06 +00:00
}
2011-06-11 12:54:26 +00:00
}
2011-05-21 22:37:15 +00:00
2014-07-06 14:16:59 +00:00
if ( startFullscreen | | Global . Config . StartFullscreen )
{
2015-12-12 19:25:59 +00:00
_needsFullscreenOnLoad = true ;
2014-07-06 14:16:59 +00:00
}
2015-11-06 14:31:50 +00:00
if ( ! Global . Game . IsNullInstance )
2012-09-03 19:42:53 +00:00
{
2015-11-06 14:31:50 +00:00
if ( cmdLoadState ! = null )
2015-10-18 02:36:04 +00:00
{
2015-11-06 14:31:50 +00:00
LoadState ( cmdLoadState , Path . GetFileName ( cmdLoadState ) ) ;
2015-10-18 02:36:04 +00:00
}
else if ( cmdLoadSlot ! = null )
{
LoadQuickSave ( "QuickSave" + cmdLoadSlot ) ;
}
else if ( Global . Config . AutoLoadLastSaveSlot )
{
LoadQuickSave ( "QuickSave" + Global . Config . SaveSlot ) ;
}
2012-09-03 19:42:53 +00:00
}
2011-02-05 21:00:59 +00:00
2014-12-19 23:33:05 +00:00
GlobalWin . Tools . AutoLoad ( ) ;
2014-12-14 01:34:58 +00:00
if ( Global . Config . RecentWatches . AutoLoad )
2012-08-15 01:03:27 +00:00
{
2013-11-28 20:02:32 +00:00
GlobalWin . Tools . LoadRamWatch ( ! Global . Config . DisplayRamWatch ) ;
2012-08-15 01:03:27 +00:00
}
2013-12-12 21:05:09 +00:00
2013-09-07 03:15:29 +00:00
if ( Global . Config . RecentCheats . AutoLoad )
{
2013-11-03 16:07:58 +00:00
GlobalWin . Tools . Load < Cheats > ( ) ;
2013-09-07 03:15:29 +00:00
}
2013-12-12 21:05:09 +00:00
2015-07-12 14:58:13 +00:00
SetStatusBar ( ) ;
2011-06-10 04:41:33 +00:00
2011-02-20 08:40:22 +00:00
if ( Global . Config . StartPaused )
2013-09-07 03:15:29 +00:00
{
2011-02-20 08:40:22 +00:00
PauseEmulator ( ) ;
2013-09-07 03:15:29 +00:00
}
2011-09-11 00:11:46 +00:00
2012-07-23 00:33:30 +00:00
// start dumping, if appropriate
if ( cmdDumpType ! = null & & cmdDumpName ! = null )
{
2014-01-10 16:54:53 +00:00
RecordAv ( cmdDumpType , cmdDumpName ) ;
2012-07-23 00:33:30 +00:00
}
2012-10-10 22:52:11 +00:00
2014-07-21 00:52:11 +00:00
SetMainformMovieInfo ( ) ;
2013-10-12 15:40:20 +00:00
2014-12-14 01:43:46 +00:00
SynchChrome ( ) ;
2015-02-22 03:53:07 +00:00
PresentationPanel . Control . Paint + = ( o , e ) = >
2013-10-12 15:40:20 +00:00
{
2016-04-20 17:17:30 +00:00
//I would like to trigger a repaint here, but this isnt done yet
2013-10-14 03:22:33 +00:00
} ;
2011-02-21 09:48:53 +00:00
}
2011-02-20 08:40:22 +00:00
2015-08-01 15:13:22 +00:00
private bool _supressSyncSettingsWarning = false ;
2015-12-15 08:22:44 +00:00
public int ProgramRunLoop ( )
2011-02-20 08:40:22 +00:00
{
2015-12-12 19:25:59 +00:00
CheckMessages ( ) ; //can someone leave a note about why this is needed?
2012-02-24 20:38:35 +00:00
LogConsole . PositionConsole ( ) ;
2015-12-12 19:25:59 +00:00
//needs to be done late, after the log console snaps on top
//fullscreen should snap on top even harder!
if ( _needsFullscreenOnLoad )
{
_needsFullscreenOnLoad = false ;
ToggleFullscreen ( ) ;
}
//incantation required to get the program reliably on top of the console window
//we might want it in ToggleFullscreen later, but here, it needs to happen regardless
BringToFront ( ) ;
Activate ( ) ;
BringToFront ( ) ;
2015-11-08 21:57:54 +00:00
for ( ; ; )
2011-02-20 08:40:22 +00:00
{
2011-07-09 22:09:39 +00:00
Input . Instance . Update ( ) ;
2013-12-20 22:05:56 +00:00
// handle events and dispatch as a hotkey action, or a hotkey button, or an input button
2011-07-10 07:39:40 +00:00
ProcessInput ( ) ;
2015-02-22 03:45:00 +00:00
Global . ClientControls . LatchFromPhysical ( HotkeyCoalescer ) ;
2014-05-17 19:35:47 +00:00
2013-12-24 21:37:51 +00:00
Global . ActiveController . LatchFromPhysical ( Global . ControllerInputCoalescer ) ;
2012-09-15 13:11:29 +00:00
2014-05-17 20:02:10 +00:00
Global . ActiveController . ApplyAxisConstraints (
2016-12-04 17:19:34 +00:00
( Emulator is N64 & & Global . Config . N64UseCircularAnalogConstraint ) ? "Natural Circle" : null ) ;
2014-05-17 19:35:47 +00:00
2013-11-01 22:56:55 +00:00
Global . ActiveController . OR_FromLogical ( Global . ClickyVirtualPadController ) ;
2013-12-24 21:37:51 +00:00
Global . AutoFireController . LatchFromPhysical ( Global . ControllerInputCoalescer ) ;
2012-09-15 13:11:29 +00:00
2013-11-03 16:47:21 +00:00
if ( Global . ClientControls [ "Autohold" ] )
2012-09-15 13:11:29 +00:00
{
2013-11-01 22:56:55 +00:00
Global . StickyXORAdapter . MassToggleStickyState ( Global . ActiveController . PressedButtons ) ;
2013-11-03 16:47:21 +00:00
Global . AutofireStickyXORAdapter . MassToggleStickyState ( Global . AutoFireController . PressedButtons ) ;
2012-09-15 13:11:29 +00:00
}
2013-11-03 16:47:21 +00:00
else if ( Global . ClientControls [ "Autofire" ] )
2013-03-09 20:10:04 +00:00
{
2013-11-03 16:47:21 +00:00
Global . AutofireStickyXORAdapter . MassToggleStickyState ( Global . ActiveController . PressedButtons ) ;
2013-03-09 20:10:04 +00:00
}
2012-09-15 13:11:29 +00:00
2014-10-19 01:22:47 +00:00
// autohold/autofire must not be affected by the following inputs
Global . ActiveController . Overrides ( Global . LuaAndAdaptor ) ;
2014-08-12 23:55:03 +00:00
2013-11-03 16:07:58 +00:00
if ( GlobalWin . Tools . Has < LuaConsole > ( ) )
2013-11-03 01:02:17 +00:00
{
2013-11-03 16:07:58 +00:00
GlobalWin . Tools . LuaConsole . ResumeScripts ( false ) ;
2013-11-03 01:02:17 +00:00
}
2012-01-28 21:43:55 +00:00
2011-02-21 09:48:53 +00:00
StepRunLoop_Core ( ) ;
2011-09-24 16:19:38 +00:00
StepRunLoop_Throttle ( ) ;
2011-06-11 12:54:26 +00:00
2016-04-20 17:17:30 +00:00
Render ( ) ;
2012-01-28 21:43:55 +00:00
2011-02-20 08:40:22 +00:00
CheckMessages ( ) ;
2014-11-12 00:11:31 +00:00
if ( _exitRequestPending )
{
_exitRequestPending = false ;
Close ( ) ;
}
2013-11-27 23:35:32 +00:00
if ( _exit )
{
2011-02-20 18:28:01 +00:00
break ;
2013-11-27 23:35:32 +00:00
}
2016-09-29 08:19:25 +00:00
if ( Global . Config . DispSpeedupFeatures ! = 0 )
{
Thread . Sleep ( 0 ) ;
}
2011-02-20 08:40:22 +00:00
}
2011-07-11 07:35:14 +00:00
Shutdown ( ) ;
2015-12-15 08:22:44 +00:00
return _exitCode ;
2011-07-11 07:35:14 +00:00
}
2013-11-03 02:51:21 +00:00
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose ( bool disposing )
2011-07-11 07:35:14 +00:00
{
2014-04-26 21:55:04 +00:00
//NOTE: this gets called twice sometimes. once by using() in Program.cs and once from winforms internals when the form is closed...
2015-11-06 14:31:50 +00:00
2013-12-20 22:05:56 +00:00
if ( GlobalWin . DisplayManager ! = null )
{
GlobalWin . DisplayManager . Dispose ( ) ;
2014-04-26 21:55:04 +00:00
GlobalWin . DisplayManager = null ;
2013-12-20 22:05:56 +00:00
}
2013-11-03 02:51:21 +00:00
if ( disposing & & ( components ! = null ) )
2011-07-11 07:35:14 +00:00
{
2013-11-03 02:51:21 +00:00
components . Dispose ( ) ;
2012-02-24 07:48:06 +00:00
}
2013-12-20 22:05:56 +00:00
2013-11-03 02:51:21 +00:00
base . Dispose ( disposing ) ;
2011-02-20 08:40:22 +00:00
}
2016-08-11 18:56:55 +00:00
#endregion
2014-01-01 03:03:10 +00:00
2015-01-24 03:10:21 +00:00
#region Pause
private bool _emulatorPaused ;
public bool EmulatorPaused
{
get
{
return _emulatorPaused ;
}
private set
{
_emulatorPaused = value ;
if ( OnPauseChanged ! = null )
{
OnPauseChanged ( this , new PauseChangedEventArgs ( _emulatorPaused ) ) ;
}
}
}
public delegate void PauseChangedEventHandler ( object sender , PauseChangedEventArgs e ) ;
public event PauseChangedEventHandler OnPauseChanged ;
public class PauseChangedEventArgs : EventArgs
{
public PauseChangedEventArgs ( bool paused )
{
Paused = paused ;
}
public bool Paused { get ; private set ; }
}
#endregion
2013-11-03 02:51:21 +00:00
#region Properties
2011-02-20 08:40:22 +00:00
2015-11-06 14:31:50 +00:00
public string CurrentlyOpenRom ; //todo - delete me and use only args instead
2015-11-19 03:18:00 +00:00
public LoadRomArgs CurrentlyOpenRomArgs ;
2013-11-03 02:51:21 +00:00
public bool PauseAVI = false ;
public bool PressFrameAdvance = false ;
2016-08-28 15:42:59 +00:00
public bool HoldFrameAdvance = false ; // necessary for tastudio > button
public bool PressRewind = false ; // necessary for tastudio < button
2013-11-03 02:51:21 +00:00
public bool FastForward = false ;
public bool TurboFastForward = false ;
public bool RestoreReadWriteOnStop = false ;
2011-02-20 08:40:22 +00:00
2014-07-27 17:49:25 +00:00
private int? _pauseOnFrame ;
public int? PauseOnFrame // If set, upon completion of this frame, the client wil pause
{
get { return _pauseOnFrame ; }
set
{
_pauseOnFrame = value ;
2014-07-27 19:07:13 +00:00
SetPauseStatusbarIcon ( ) ;
2014-08-31 16:51:19 +00:00
if ( value = = null ) // TODO: make an Event handler instead, but the logic here is that after turbo seeking, tools will want to do a real update when the emulator finally pauses
{
2015-10-22 16:33:04 +00:00
bool skipScripts = ! ( Global . Config . TurboSeek & & ! Global . Config . RunLuaDuringTurbo ) ;
GlobalWin . Tools . UpdateToolsBefore ( skipScripts ) ;
GlobalWin . Tools . UpdateToolsAfter ( skipScripts ) ;
2014-08-31 16:51:19 +00:00
}
2014-07-27 17:49:25 +00:00
}
2014-07-27 19:07:13 +00:00
}
public bool IsSeeking
{
get { return PauseOnFrame . HasValue ; }
}
public bool IsTurboSeeking
{
get
{
return PauseOnFrame . HasValue & & Global . Config . TurboSeek ;
}
}
2014-07-27 17:49:25 +00:00
public bool IsTurboing
{
get
{
2014-07-27 19:07:13 +00:00
return Global . ClientControls [ "Turbo" ] | | IsTurboSeeking ;
2014-07-27 17:49:25 +00:00
}
}
2014-07-26 12:47:09 +00:00
2013-11-03 02:51:21 +00:00
#endregion
#region Public Methods
2014-01-21 00:36:22 +00:00
public void ClearHolds ( )
{
Global . StickyXORAdapter . ClearStickies ( ) ;
Global . AutofireStickyXORAdapter . ClearStickies ( ) ;
2014-06-22 13:57:23 +00:00
if ( GlobalWin . Tools . Has < VirtualpadTool > ( ) )
2014-01-21 00:36:22 +00:00
{
GlobalWin . Tools . VirtualPad . ClearVirtualPadHolds ( ) ;
}
}
2013-11-27 23:35:32 +00:00
public void FlagNeedsReboot ( )
{
RebootStatusBarIcon . Visible = true ;
GlobalWin . OSD . AddMessage ( "Core reboot needed for this setting" ) ;
}
2013-11-03 02:51:21 +00:00
/// <summary>
/// Controls whether the app generates input events. should be turned off for most modal dialogs
/// </summary>
2015-12-05 17:32:56 +00:00
public bool AllowInput ( bool yield_alt )
2011-06-11 12:54:26 +00:00
{
2015-12-05 17:32:56 +00:00
// the main form gets input
if ( ActiveForm = = this )
2012-09-03 20:17:57 +00:00
{
2015-12-05 17:32:56 +00:00
return true ;
}
2013-11-03 02:51:21 +00:00
2015-12-05 17:32:56 +00:00
//even more special logic for TAStudio:
//TODO - implement by event filter in TAStudio
if ( ActiveForm is TAStudio )
{
if ( yield_alt ) return false ;
var ts = ActiveForm as TAStudio ;
2016-11-21 15:00:21 +00:00
if ( ts . IsInMenuLoop )
2015-12-05 17:32:56 +00:00
return false ;
}
2013-12-20 22:05:56 +00:00
2015-12-05 17:32:56 +00:00
// modals that need to capture input for binding purposes get input, of course
if ( ActiveForm is HotkeyConfig | |
ActiveForm is ControllerConfig | |
ActiveForm is TAStudio | |
ActiveForm is VirtualpadTool )
{
return true ;
}
2013-11-03 02:51:21 +00:00
2015-12-05 17:32:56 +00:00
// if no form is active on this process, then the background input setting applies
if ( ActiveForm = = null & & Global . Config . AcceptBackgroundInput )
{
return true ;
2012-09-03 20:17:57 +00:00
}
2015-12-05 17:32:56 +00:00
return false ;
2012-09-29 22:37:34 +00:00
}
2011-06-19 20:50:46 +00:00
2016-12-04 17:19:34 +00:00
// TODO: make this an actual property, set it when loading a Rom, and pass it dialogs, etc
// This is a quick hack to reduce the dependency on Global.Emulator
public IEmulator Emulator
{
get { return Global . Emulator ; }
2016-12-07 19:21:18 +00:00
set
{
Global . Emulator = value ;
2016-12-12 19:47:11 +00:00
_currentVideoProvider = Global . Emulator . AsVideoProviderOrDefault ( ) ;
2016-12-11 19:07:12 +00:00
_currentSoundProvider = Global . Emulator . AsSoundProviderOrDefault ( ) ;
2016-12-07 19:21:18 +00:00
}
2016-12-04 17:19:34 +00:00
}
2014-06-22 23:20:36 +00:00
2016-12-07 19:21:18 +00:00
private IVideoProvider _currentVideoProvider = NullVideo . Instance ;
2016-12-11 17:14:42 +00:00
private ISoundProvider _currentSoundProvider = new NullSound ( 44100 / 60 ) ; // Reasonable default until we have a core instance
2014-06-22 23:20:36 +00:00
protected override void OnActivated ( EventArgs e )
{
base . OnActivated ( e ) ;
Input . Instance . ControlInputFocus ( this , Input . InputFocus . Mouse , true ) ;
}
protected override void OnDeactivate ( EventArgs e )
{
Input . Instance . ControlInputFocus ( this , Input . InputFocus . Mouse , false ) ;
2014-07-06 21:20:43 +00:00
base . OnDeactivate ( e ) ;
2014-06-22 23:20:36 +00:00
}
2013-11-03 02:51:21 +00:00
public void ProcessInput ( )
2012-09-29 22:37:34 +00:00
{
2013-12-24 21:37:51 +00:00
ControllerInputCoalescer conInput = Global . ControllerInputCoalescer as ControllerInputCoalescer ;
2015-11-08 21:57:54 +00:00
for ( ; ; )
2013-11-03 02:51:21 +00:00
{
2014-01-01 03:03:10 +00:00
2013-12-20 22:05:56 +00:00
// loop through all available events
2013-11-03 02:51:21 +00:00
var ie = Input . Instance . DequeueEvent ( ) ;
if ( ie = = null ) { break ; }
2013-12-20 22:05:56 +00:00
// useful debugging:
// Console.WriteLine(ie);
2013-11-03 02:51:21 +00:00
2013-12-20 22:05:56 +00:00
// TODO - wonder what happens if we pop up something interactive as a response to one of these hotkeys? may need to purge further processing
2013-11-03 02:51:21 +00:00
2013-12-20 22:05:56 +00:00
// look for hotkey bindings for this key
2013-11-03 16:47:21 +00:00
var triggers = Global . ClientControls . SearchBindings ( ie . LogicalButton . ToString ( ) ) ;
2013-11-03 02:51:21 +00:00
if ( triggers . Count = = 0 )
{
2013-12-20 22:05:56 +00:00
// Maybe it is a system alt-key which hasnt been overridden
2013-11-03 02:51:21 +00:00
if ( ie . EventType = = Input . InputEventType . Press )
{
if ( ie . LogicalButton . Alt & & ie . LogicalButton . Button . Length = = 1 )
{
2013-11-27 23:35:32 +00:00
var c = ie . LogicalButton . Button . ToLower ( ) [ 0 ] ;
2013-12-20 22:05:56 +00:00
if ( ( c > = 'a' & & c < = 'z' ) | | c = = ' ' )
2013-11-03 02:51:21 +00:00
{
SendAltKeyChar ( c ) ;
}
}
if ( ie . LogicalButton . Alt & & ie . LogicalButton . Button = = "Space" )
{
SendPlainAltKey ( 32 ) ;
}
}
2013-12-20 22:05:56 +00:00
// ordinarily, an alt release with nothing else would move focus to the menubar. but that is sort of useless, and hard to implement exactly right.
2013-11-03 02:51:21 +00:00
}
2013-12-20 22:05:56 +00:00
// zero 09-sep-2012 - all input is eligible for controller input. not sure why the above was done.
// maybe because it doesnt make sense to me to bind hotkeys and controller inputs to the same keystrokes
2013-11-03 02:51:21 +00:00
2013-12-20 22:05:56 +00:00
// adelikat 02-dec-2012 - implemented options for how to handle controller vs hotkey conflicts. This is primarily motivated by computer emulation and thus controller being nearly the entire keyboard
2013-11-03 02:51:21 +00:00
bool handled ;
switch ( Global . Config . Input_Hotkey_OverrideOptions )
{
default :
2013-12-20 22:05:56 +00:00
case 0 : // Both allowed
2013-12-24 21:37:51 +00:00
conInput . Receive ( ie ) ;
2013-11-03 02:51:21 +00:00
handled = false ;
if ( ie . EventType = = Input . InputEventType . Press )
{
handled = triggers . Aggregate ( handled , ( current , trigger ) = > current | CheckHotkey ( trigger ) ) ;
}
2013-12-20 22:05:56 +00:00
// hotkeys which arent handled as actions get coalesced as pollable virtual client buttons
2013-11-03 02:51:21 +00:00
if ( ! handled )
{
2015-02-22 03:45:00 +00:00
HotkeyCoalescer . Receive ( ie ) ;
2013-11-03 02:51:21 +00:00
}
2013-12-20 22:05:56 +00:00
2013-11-03 02:51:21 +00:00
break ;
2013-12-20 22:05:56 +00:00
case 1 : // Input overrides Hokeys
2013-12-24 21:37:51 +00:00
conInput . Receive ( ie ) ;
2013-12-20 22:05:56 +00:00
if ( ! Global . ActiveController . HasBinding ( ie . LogicalButton . ToString ( ) ) )
2013-11-03 02:51:21 +00:00
{
handled = false ;
if ( ie . EventType = = Input . InputEventType . Press )
{
handled = triggers . Aggregate ( handled , ( current , trigger ) = > current | CheckHotkey ( trigger ) ) ;
}
2013-12-20 22:05:56 +00:00
// hotkeys which arent handled as actions get coalesced as pollable virtual client buttons
2013-11-03 02:51:21 +00:00
if ( ! handled )
{
2015-02-22 03:45:00 +00:00
HotkeyCoalescer . Receive ( ie ) ;
2013-11-03 02:51:21 +00:00
}
}
break ;
2013-12-20 22:05:56 +00:00
case 2 : // Hotkeys override Input
2013-11-03 02:51:21 +00:00
handled = false ;
if ( ie . EventType = = Input . InputEventType . Press )
{
handled = triggers . Aggregate ( handled , ( current , trigger ) = > current | CheckHotkey ( trigger ) ) ;
}
2013-12-20 22:05:56 +00:00
// hotkeys which arent handled as actions get coalesced as pollable virtual client buttons
2013-11-03 02:51:21 +00:00
if ( ! handled )
{
2015-02-22 03:45:00 +00:00
HotkeyCoalescer . Receive ( ie ) ;
2013-12-24 21:37:51 +00:00
conInput . Receive ( ie ) ;
2013-11-03 02:51:21 +00:00
}
2013-12-20 22:05:56 +00:00
2013-11-03 02:51:21 +00:00
break ;
}
2013-12-20 22:05:56 +00:00
} // foreach event
2013-11-03 02:51:21 +00:00
// also handle floats
2014-04-16 01:47:37 +00:00
conInput . AcceptNewFloats ( Input . Instance . GetFloats ( ) . Select ( o = >
2014-05-04 14:10:28 +00:00
{
// hackish
if ( o . Item1 = = "WMouse X" )
2014-04-16 01:47:37 +00:00
{
2014-06-29 02:28:48 +00:00
var P = GlobalWin . DisplayManager . UntransformPoint ( new Point ( ( int ) o . Item2 , 0 ) ) ;
2016-12-07 19:21:18 +00:00
float x = P . X / ( float ) _currentVideoProvider . BufferWidth ;
2014-05-04 14:10:28 +00:00
return new Tuple < string , float > ( "WMouse X" , x * 20000 - 10000 ) ;
}
2015-11-06 14:31:50 +00:00
2014-05-04 14:10:28 +00:00
if ( o . Item1 = = "WMouse Y" )
{
2014-06-29 02:28:48 +00:00
var P = GlobalWin . DisplayManager . UntransformPoint ( new Point ( 0 , ( int ) o . Item2 ) ) ;
2016-12-07 19:21:18 +00:00
float y = P . Y / ( float ) _currentVideoProvider . BufferHeight ;
2014-05-04 14:10:28 +00:00
return new Tuple < string , float > ( "WMouse Y" , y * 20000 - 10000 ) ;
}
2015-11-06 14:31:50 +00:00
2014-05-04 14:10:28 +00:00
return o ;
} ) ) ;
2011-06-11 12:54:26 +00:00
}
2011-05-22 18:38:44 +00:00
2013-11-03 02:51:21 +00:00
public void RebootCore ( )
2011-02-20 08:40:22 +00:00
{
2016-02-28 17:15:23 +00:00
var ioa = OpenAdvancedSerializer . ParseWithLegacy ( CurrentlyOpenRomPoopForAdvancedLoaderPleaseRefactorME ) ;
2015-11-07 19:05:40 +00:00
if ( ioa is OpenAdvanced_LibretroNoGame )
2015-11-06 14:31:50 +00:00
LoadRom ( "" , CurrentlyOpenRomArgs ) ;
else
LoadRom ( ioa . SimplePath , CurrentlyOpenRomArgs ) ;
2011-02-20 08:40:22 +00:00
}
2013-11-03 02:51:21 +00:00
public void PauseEmulator ( )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
EmulatorPaused = true ;
SetPauseStatusbarIcon ( ) ;
}
2011-07-13 01:29:13 +00:00
2013-11-03 02:51:21 +00:00
public void UnpauseEmulator ( )
{
EmulatorPaused = false ;
SetPauseStatusbarIcon ( ) ;
2011-06-11 12:54:26 +00:00
}
2011-05-19 18:50:09 +00:00
2013-11-03 02:51:21 +00:00
public void TogglePause ( )
2011-02-20 08:40:22 +00:00
{
2013-11-03 02:51:21 +00:00
EmulatorPaused ^ = true ;
SetPauseStatusbarIcon ( ) ;
2014-07-27 19:07:13 +00:00
// TODO: have tastudio set a pause status change callback, or take control over pause
if ( GlobalWin . Tools . Has < TAStudio > ( ) )
{
GlobalWin . Tools . UpdateValues < TAStudio > ( ) ;
}
2013-11-03 02:51:21 +00:00
}
2011-04-11 01:30:11 +00:00
2015-07-19 02:20:38 +00:00
public byte [ ] CurrentFrameBuffer ( bool captureOSD )
{
using ( var bb = captureOSD ? CaptureOSD ( ) : MakeScreenshotImage ( ) )
{
using ( var img = bb . ToSysdrawingBitmap ( ) )
{
ImageConverter converter = new ImageConverter ( ) ;
return ( byte [ ] ) converter . ConvertTo ( img , typeof ( byte [ ] ) ) ;
}
}
}
2013-11-03 02:51:21 +00:00
public void TakeScreenshotToClipboard ( )
2011-06-11 12:54:26 +00:00
{
2014-06-02 20:16:59 +00:00
using ( var bb = Global . Config . Screenshot_CaptureOSD ? CaptureOSD ( ) : MakeScreenshotImage ( ) )
2013-11-03 02:51:21 +00:00
{
2015-11-06 14:31:50 +00:00
using ( var img = bb . ToSysdrawingBitmap ( ) )
2014-06-02 20:16:59 +00:00
Clipboard . SetImage ( img ) ;
2013-11-03 02:51:21 +00:00
}
2013-12-20 22:05:56 +00:00
2014-07-22 00:04:28 +00:00
GlobalWin . OSD . AddMessage ( "Screenshot (raw) saved to clipboard." ) ;
2011-06-11 12:54:26 +00:00
}
2011-05-13 17:03:05 +00:00
2016-02-15 02:30:24 +00:00
public void TakeScreenshotClientToClipboard ( )
{
2016-12-07 19:21:18 +00:00
using ( var bb = GlobalWin . DisplayManager . RenderOffscreen ( _currentVideoProvider , Global . Config . Screenshot_CaptureOSD ) )
2016-02-15 02:30:24 +00:00
{
using ( var img = bb . ToSysdrawingBitmap ( ) )
Clipboard . SetImage ( img ) ;
}
GlobalWin . OSD . AddMessage ( "Screenshot (client) saved to clipboard." ) ;
}
2013-11-03 02:51:21 +00:00
public void TakeScreenshot ( )
2011-02-20 08:40:22 +00:00
{
2015-08-05 14:47:00 +00:00
string fmt = "{0}.{1:yyyy-MM-dd HH.mm.ss}{2}.png" ;
string prefix = PathManager . ScreenshotPrefix ( Global . Game ) ;
var ts = DateTime . Now ;
string fname_bare = string . Format ( fmt , prefix , ts , "" ) ;
string fname = string . Format ( fmt , prefix , ts , " (0)" ) ;
2015-10-12 21:35:45 +00:00
//if the (0) filename exists, do nothing. we'll bump up the number later
//if the bare filename exists, move it to (0)
//otherwise, no related filename exists, and we can proceed with the bare filename
if ( File . Exists ( fname ) ) { }
else if ( File . Exists ( fname_bare ) )
2015-08-05 14:47:00 +00:00
File . Move ( fname_bare , fname ) ;
else fname = fname_bare ;
int seq = 0 ;
while ( File . Exists ( fname ) )
{
var sequence = string . Format ( " ({0})" , seq + + ) ;
fname = string . Format ( fmt , prefix , ts , sequence ) ;
2015-11-06 14:31:50 +00:00
}
2015-08-05 14:47:00 +00:00
TakeScreenshot ( fname ) ;
2011-02-20 08:40:22 +00:00
}
2013-11-03 02:51:21 +00:00
public void TakeScreenshot ( string path )
2011-02-20 08:40:22 +00:00
{
2013-11-03 02:51:21 +00:00
var fi = new FileInfo ( path ) ;
if ( fi . Directory ! = null & & fi . Directory . Exists = = false )
2013-12-20 22:05:56 +00:00
{
2013-11-03 02:51:21 +00:00
fi . Directory . Create ( ) ;
2013-12-20 22:05:56 +00:00
}
2014-06-02 20:16:59 +00:00
using ( var bb = Global . Config . Screenshot_CaptureOSD ? CaptureOSD ( ) : MakeScreenshotImage ( ) )
2011-02-20 08:40:22 +00:00
{
2015-02-01 22:49:53 +00:00
using ( var img = bb . ToSysdrawingBitmap ( ) )
2014-06-02 20:16:59 +00:00
img . Save ( fi . FullName , ImageFormat . Png ) ;
2011-02-20 08:40:22 +00:00
}
2015-02-01 22:49:53 +00:00
/ *
using ( var fs = new FileStream ( path + "_test.bmp" , FileMode . OpenOrCreate , FileAccess . Write ) )
2016-12-04 17:19:34 +00:00
QuickBmpFile . Save ( Emulator . VideoProvider ( ) , fs , r . Next ( 50 , 500 ) , r . Next ( 50 , 500 ) ) ;
2015-02-01 22:49:53 +00:00
* /
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( fi . Name + " saved." ) ;
2011-02-20 08:40:22 +00:00
}
2015-02-01 22:49:53 +00:00
//static Random r = new Random();
2011-02-20 08:40:22 +00:00
2013-11-03 02:51:21 +00:00
public void FrameBufferResized ( )
2013-07-14 01:48:05 +00:00
{
2013-11-03 02:51:21 +00:00
// run this entire thing exactly twice, since the first resize may adjust the menu stacking
for ( int i = 0 ; i < 2 ; i + + )
2013-07-14 01:48:05 +00:00
{
2016-12-04 17:19:34 +00:00
int zoom = Global . Config . TargetZoomFactors [ Emulator . SystemId ] ;
2013-11-03 02:51:21 +00:00
var area = Screen . FromControl ( this ) . WorkingArea ;
2015-02-22 03:53:07 +00:00
int borderWidth = Size . Width - PresentationPanel . Control . Size . Width ;
int borderHeight = Size . Height - PresentationPanel . Control . Size . Height ;
2013-11-03 02:51:21 +00:00
// start at target zoom and work way down until we find acceptable zoom
2014-05-17 03:50:19 +00:00
Size lastComputedSize = new Size ( 1 , 1 ) ;
2013-11-03 02:51:21 +00:00
for ( ; zoom > = 1 ; zoom - - )
2013-07-14 01:48:05 +00:00
{
2016-12-07 19:21:18 +00:00
lastComputedSize = GlobalWin . DisplayManager . CalculateClientSize ( _currentVideoProvider , zoom ) ;
2014-05-17 03:50:19 +00:00
if ( ( ( ( lastComputedSize . Width ) + borderWidth ) < area . Width )
& & ( ( ( lastComputedSize . Height ) + borderHeight ) < area . Height ) )
2013-12-20 22:05:56 +00:00
{
2013-11-03 02:51:21 +00:00
break ;
2013-12-20 22:05:56 +00:00
}
2013-07-14 01:48:05 +00:00
}
2014-12-10 19:36:16 +00:00
Console . WriteLine ( "Selecting display size " + lastComputedSize . ToString ( ) ) ;
2013-11-03 02:51:21 +00:00
// Change size
2014-05-17 03:50:19 +00:00
Size = new Size ( ( lastComputedSize . Width ) + borderWidth , ( ( lastComputedSize . Height ) + borderHeight ) ) ;
2013-11-03 02:51:21 +00:00
PerformLayout ( ) ;
2015-02-22 03:53:07 +00:00
PresentationPanel . Resized = true ;
2013-11-03 02:51:21 +00:00
// Is window off the screen at this size?
if ( area . Contains ( Bounds ) = = false )
2013-07-24 02:14:25 +00:00
{
2013-11-03 02:51:21 +00:00
if ( Bounds . Right > area . Right ) // Window is off the right edge
2013-12-20 22:05:56 +00:00
{
2013-11-03 02:51:21 +00:00
Location = new Point ( area . Right - Size . Width , Location . Y ) ;
2013-12-20 22:05:56 +00:00
}
2013-11-03 02:51:21 +00:00
if ( Bounds . Bottom > area . Bottom ) // Window is off the bottom edge
2013-12-20 22:05:56 +00:00
{
2013-11-03 02:51:21 +00:00
Location = new Point ( Location . X , area . Bottom - Size . Height ) ;
2013-12-20 22:05:56 +00:00
}
2013-07-24 02:14:25 +00:00
}
}
2013-07-14 01:48:05 +00:00
}
2013-07-24 02:14:25 +00:00
2014-05-06 01:27:56 +00:00
public bool IsInFullscreen
{
get { return _inFullscreen ; }
}
2014-12-14 01:43:46 +00:00
public void SynchChrome ( )
{
if ( _inFullscreen )
{
//TODO - maybe apply a hack tracked during fullscreen here to override it
FormBorderStyle = FormBorderStyle . None ;
MainMenuStrip . Visible = Global . Config . DispChrome_MenuFullscreen & & ! _chromeless ;
MainStatusBar . Visible = Global . Config . DispChrome_StatusBarFullscreen & & ! _chromeless ;
}
else
{
MainStatusBar . Visible = Global . Config . DispChrome_StatusBarWindowed & & ! _chromeless ;
MainMenuStrip . Visible = Global . Config . DispChrome_MenuWindowed & & ! _chromeless ;
MaximizeBox = MinimizeBox = Global . Config . DispChrome_CaptionWindowed & & ! _chromeless ;
if ( Global . Config . DispChrome_FrameWindowed = = 0 | | _chromeless )
FormBorderStyle = System . Windows . Forms . FormBorderStyle . None ;
else if ( Global . Config . DispChrome_FrameWindowed = = 1 )
FormBorderStyle = System . Windows . Forms . FormBorderStyle . SizableToolWindow ;
else if ( Global . Config . DispChrome_FrameWindowed = = 2 )
FormBorderStyle = System . Windows . Forms . FormBorderStyle . Sizable ;
}
}
2015-11-06 14:31:50 +00:00
public void ToggleFullscreen ( bool allowSuppress = false )
2013-07-14 01:48:05 +00:00
{
2015-07-24 20:59:53 +00:00
AutohideCursor ( false ) ;
2014-05-17 02:55:58 +00:00
//prohibit this operation if the current controls include LMouse
if ( allowSuppress )
{
if ( Global . ActiveController . HasBinding ( "WMouse L" ) )
return ;
}
2013-11-27 23:35:32 +00:00
if ( _inFullscreen = = false )
2013-07-14 01:48:05 +00:00
{
2014-02-04 21:06:00 +00:00
SuspendLayout ( ) ;
2015-11-06 14:31:50 +00:00
#if WINDOWS
//Work around an AMD driver bug in >= vista:
//It seems windows will activate opengl fullscreen mode when a GL control is occupying the exact space of a screen (0,0 and dimensions=screensize)
//AMD cards manifest a problem under these circumstances, flickering other monitors.
//It isnt clear whether nvidia cards are failing to employ this optimization, or just not flickering.
//(this could be determined with more work; other side affects of the fullscreen mode include: corrupted taskbar, no modal boxes on top of GL control, no screenshots)
//At any rate, we can solve this by adding a 1px black border around the GL control
//Please note: It is important to do this before resizing things, otherwise momentarily a GL control without WS_BORDER will be at the magic dimensions and cause the flakeout
2016-03-24 19:47:03 +00:00
if ( Global . Config . DispFullscreenHacks & & Global . Config . DispMethod = = Config . EDispMethod . OpenGL )
2015-11-06 14:31:50 +00:00
{
//ATTENTION: this causes the statusbar to not work well, since the backcolor is now set to black instead of SystemColors.Control.
//It seems that some statusbar elements composite with the backcolor.
//Maybe we could add another control under the statusbar. with a different backcolor
Padding = new Padding ( 1 ) ;
BackColor = Color . Black ;
2016-03-24 19:47:03 +00:00
//FUTURE WORK:
//re-add this padding back into the display manager (so the image will get cut off a little but, but a few more resolutions will fully fit into the screen)
2015-11-06 14:31:50 +00:00
}
#endif
2014-02-04 00:41:24 +00:00
2014-01-10 16:54:53 +00:00
_windowedLocation = Location ;
2014-12-14 01:43:46 +00:00
_inFullscreen = true ;
SynchChrome ( ) ;
WindowState = FormWindowState . Maximized ; //be sure to do this after setting the chrome, otherwise it wont work fully
2014-02-04 21:06:00 +00:00
ResumeLayout ( ) ;
2014-02-04 00:41:24 +00:00
2015-02-22 03:53:07 +00:00
PresentationPanel . Resized = true ;
2013-11-03 02:51:21 +00:00
}
else
{
2014-02-04 21:06:00 +00:00
SuspendLayout ( ) ;
2013-11-03 02:51:21 +00:00
WindowState = FormWindowState . Normal ;
2014-02-04 01:37:43 +00:00
2015-11-06 14:31:50 +00:00
#if WINDOWS
//do this even if DispFullscreenHacks arent enabled, to restore it in case it changed underneath us or something
Padding = new Padding ( 0 ) ;
//it's important that we set the form color back to this, because the statusbar icons blend onto the mainform, not onto the statusbar--
//so we need the statusbar and mainform backdrop color to match
BackColor = SystemColors . Control ;
#endif
2014-02-04 01:37:43 +00:00
2014-12-14 01:43:46 +00:00
_inFullscreen = false ;
2015-11-06 14:31:50 +00:00
2014-12-14 01:43:46 +00:00
SynchChrome ( ) ;
2014-01-10 16:54:53 +00:00
Location = _windowedLocation ;
2014-02-04 21:06:00 +00:00
ResumeLayout ( ) ;
2014-02-04 00:41:24 +00:00
2013-11-03 02:51:21 +00:00
FrameBufferResized ( ) ;
2013-07-14 01:48:05 +00:00
}
}
2013-11-03 02:51:21 +00:00
public void OpenLuaConsole ( )
2011-04-06 05:43:59 +00:00
{
2013-11-03 02:51:21 +00:00
#if WINDOWS
2013-11-03 16:07:58 +00:00
GlobalWin . Tools . Load < LuaConsole > ( ) ;
2013-11-03 02:51:21 +00:00
#else
MessageBox . Show ( "Sorry, Lua is not supported on this platform." , "Lua not supported" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
#endif
}
2013-07-14 01:48:05 +00:00
2013-11-03 02:51:21 +00:00
public void NotifyLogWindowClosing ( )
{
DisplayLogWindowMenuItem . Checked = false ;
}
2013-07-14 01:48:05 +00:00
2013-11-03 02:51:21 +00:00
public void ClickSpeedItem ( int num )
{
2013-12-20 22:05:56 +00:00
if ( ( ModifierKeys & Keys . Control ) ! = 0 )
{
SetSpeedPercentAlternate ( num ) ;
}
else
{
SetSpeedPercent ( num ) ;
}
2013-11-03 02:51:21 +00:00
}
2011-08-08 23:35:13 +00:00
2015-09-06 22:00:39 +00:00
public void Unthrottle ( )
{
_unthrottled = true ;
}
public void Throttle ( )
{
_unthrottled = false ;
}
2015-08-18 04:49:24 +00:00
void ThrottleMessage ( )
{
string ttype = ":(none)" ;
2015-09-06 22:00:39 +00:00
if ( Global . Config . SoundThrottle ) { ttype = ":Sound" ; }
2015-11-06 14:31:50 +00:00
if ( Global . Config . VSyncThrottle ) { ttype = string . Format ( ":Vsync{0}" , Global . Config . VSync ? "[ena]" : "[dis]" ) ; }
2015-09-06 22:00:39 +00:00
if ( Global . Config . ClockThrottle ) { ttype = ":Clock" ; }
2015-08-18 04:49:24 +00:00
string xtype = _unthrottled ? "Unthrottled" : "Throttled" ;
2015-09-06 22:00:39 +00:00
string msg = string . Format ( "{0}{1} " , xtype , ttype ) ;
2015-08-18 04:49:24 +00:00
GlobalWin . OSD . AddMessage ( msg ) ;
}
2013-11-03 02:51:21 +00:00
public void FrameSkipMessage ( )
{
2013-11-27 23:35:32 +00:00
GlobalWin . OSD . AddMessage ( "Frameskipping set to " + Global . Config . FrameSkip ) ;
2013-11-03 02:51:21 +00:00
}
2011-07-24 23:14:16 +00:00
2013-11-03 02:51:21 +00:00
public void UpdateCheatStatus ( )
{
if ( Global . CheatList . ActiveCount > 0 )
{
CheatStatusButton . ToolTipText = "Cheats are currently active" ;
CheatStatusButton . Image = Properties . Resources . Freeze ;
CheatStatusButton . Visible = true ;
}
2011-07-24 23:14:16 +00:00
else
2013-11-03 02:51:21 +00:00
{
2014-05-12 20:51:09 +00:00
CheatStatusButton . ToolTipText = string . Empty ;
2013-11-03 02:51:21 +00:00
CheatStatusButton . Image = Properties . Resources . Blank ;
CheatStatusButton . Visible = false ;
}
2011-04-06 05:43:59 +00:00
}
2016-12-04 17:19:34 +00:00
private LibsnesCore AsSNES { get { return Emulator as LibsnesCore ; } }
2014-10-19 01:22:47 +00:00
2014-11-29 21:06:15 +00:00
// TODO: Clean Me!
2013-11-03 02:51:21 +00:00
public void SNES_ToggleBG1 ( bool? setto = null )
2011-02-20 08:40:22 +00:00
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2011-01-20 06:24:31 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowBG1_1 = s . ShowBG1_0 = setto . Value ;
2013-11-27 23:35:32 +00:00
}
else
{
2013-12-27 17:59:19 +00:00
s . ShowBG1_1 = s . ShowBG1_0 ^ = true ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowBG1_1 ? "BG 1 Layer On" : "BG 1 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2011-03-07 01:07:49 +00:00
2013-11-03 02:51:21 +00:00
public void SNES_ToggleBG2 ( bool? setto = null )
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2013-11-03 02:51:21 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowBG2_1 = s . ShowBG2_0 = setto . Value ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
else
{
2013-12-27 17:59:19 +00:00
s . ShowBG2_1 = s . ShowBG2_0 ^ = true ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowBG2_1 ? "BG 2 Layer On" : "BG 2 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2011-03-07 02:04:42 +00:00
2013-11-03 02:51:21 +00:00
public void SNES_ToggleBG3 ( bool? setto = null )
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2013-11-03 02:51:21 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowBG3_1 = s . ShowBG3_0 = setto . Value ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
else
{
2013-12-27 17:59:19 +00:00
s . ShowBG3_1 = s . ShowBG3_0 ^ = true ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowBG3_1 ? "BG 3 Layer On" : "BG 3 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2011-03-07 02:04:42 +00:00
2013-11-03 02:51:21 +00:00
public void SNES_ToggleBG4 ( bool? setto = null )
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2013-11-03 02:51:21 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowBG4_1 = s . ShowBG4_0 = setto . Value ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
else
{
2013-12-27 17:59:19 +00:00
s . ShowBG4_1 = s . ShowBG4_0 ^ = true ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowBG4_1 ? "BG 4 Layer On" : "BG 4 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2011-03-07 01:07:49 +00:00
2013-12-29 23:35:42 +00:00
public void SNES_ToggleObj1 ( bool? setto = null )
2013-11-03 02:51:21 +00:00
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2013-11-03 02:51:21 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_0 = setto . Value ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
else
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_0 ^ = true ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowOBJ_0 ? "OBJ 1 Layer On" : "OBJ 1 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2011-08-09 00:51:46 +00:00
2013-12-29 23:35:42 +00:00
public void SNES_ToggleObj2 ( bool? setto = null )
2013-11-03 02:51:21 +00:00
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2013-11-03 02:51:21 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_1 = setto . Value ;
2013-11-27 23:35:32 +00:00
}
else
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_1 ^ = true ;
2013-11-03 02:51:21 +00:00
}
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowOBJ_1 ? "OBJ 2 Layer On" : "OBJ 2 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2013-09-07 01:38:24 +00:00
2013-11-03 02:51:21 +00:00
public void SNES_ToggleOBJ3 ( bool? setto = null )
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2013-11-03 02:51:21 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_2 = setto . Value ;
2013-11-27 23:35:32 +00:00
}
else
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_2 ^ = true ;
2013-11-03 02:51:21 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowOBJ_2 ? "OBJ 3 Layer On" : "OBJ 3 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2011-08-09 00:51:46 +00:00
2013-11-03 02:51:21 +00:00
public void SNES_ToggleOBJ4 ( bool? setto = null )
{
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is LibsnesCore ) ) return ;
2014-10-19 01:22:47 +00:00
var s = AsSNES . GetSettings ( ) ;
2013-11-27 23:35:32 +00:00
if ( setto . HasValue )
2013-11-03 02:51:21 +00:00
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_3 = setto . Value ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
else
{
2013-12-27 17:59:19 +00:00
s . ShowOBJ_3 ^ = true ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-19 01:22:47 +00:00
AsSNES . PutSettings ( s ) ;
2013-12-27 17:59:19 +00:00
GlobalWin . OSD . AddMessage ( s . ShowOBJ_3 ? "OBJ 4 Layer On" : "OBJ 4 Layer Off" ) ;
2013-11-03 02:51:21 +00:00
}
2012-03-03 21:51:20 +00:00
2013-11-03 02:51:21 +00:00
#endregion
2011-08-30 04:02:52 +00:00
2013-11-03 02:51:21 +00:00
#region Private variables
2011-08-30 04:02:52 +00:00
2014-05-18 02:11:17 +00:00
private Size _lastVideoSize = new Size ( - 1 , - 1 ) , _lastVirtualSize = new Size ( - 1 , - 1 ) ;
2013-11-27 23:35:32 +00:00
private readonly SaveSlotManager _stateSlots = new SaveSlotManager ( ) ;
2011-08-30 04:02:52 +00:00
2013-12-20 22:05:56 +00:00
// AVI/WAV state
2013-11-27 23:35:32 +00:00
private IVideoWriter _currAviWriter ;
2015-01-27 04:05:20 +00:00
private HashSet < int > _currAviWriterFrameList ;
2016-12-11 17:14:42 +00:00
// Sound refator TODO: we can enforce async mode here with a property that gets/sets this but does an async check
private ISoundProvider _aviSoundInputAsync ; // Note: This sound provider must be in async mode!
2016-12-12 03:37:28 +00:00
private SimpleSyncSoundProvider _dumpProxy ; // an audio proxy used for dumping
2014-10-11 03:33:09 +00:00
private bool _dumpaudiosync ; // set true to for experimental AV dumping
2013-11-27 23:35:32 +00:00
private int _avwriterResizew ;
private int _avwriterResizeh ;
2014-02-07 02:28:07 +00:00
private bool _avwriterpad ;
2013-12-29 23:35:42 +00:00
2013-11-27 23:35:32 +00:00
private bool _exit ;
2015-12-15 08:22:44 +00:00
private int _exitCode ;
2014-11-12 00:11:31 +00:00
private bool _exitRequestPending ;
2013-11-27 23:35:32 +00:00
private bool _runloopFrameProgress ;
2015-01-31 22:16:02 +00:00
private long _frameAdvanceTimestamp ;
private long _frameRewindTimestamp ;
2016-09-29 04:16:24 +00:00
private double _runloopLastFps ;
2016-09-29 07:04:39 +00:00
private double _runloopDisplayFps ;
2016-09-29 04:16:24 +00:00
private bool _runloopFrameadvance ;
2016-09-29 07:04:39 +00:00
private double _runloopUpdatesPerSecond = 12.0 ;
2016-09-29 04:16:24 +00:00
private double _runloopFpsSmoothing = 8.0 ;
private long _runloopSecond ;
2013-11-27 23:35:32 +00:00
private bool _runloopLastFf ;
2014-09-14 00:51:30 +00:00
private bool _inResizeLoop ;
2011-08-30 04:02:52 +00:00
2013-11-27 23:35:32 +00:00
private readonly Throttle _throttle ;
private bool _unthrottled ;
2011-09-24 16:09:40 +00:00
2013-12-20 22:05:56 +00:00
// For handling automatic pausing when entering the menu
2013-11-27 23:35:32 +00:00
private bool _wasPaused ;
private bool _didMenuPause ;
2011-09-19 00:39:28 +00:00
2015-07-24 20:59:53 +00:00
private Cursor _blankCursor ;
private bool _cursorHidden ;
2013-11-27 23:35:32 +00:00
private bool _inFullscreen ;
2013-12-29 23:35:42 +00:00
private Point _windowedLocation ;
2015-12-12 19:25:59 +00:00
private bool _needsFullscreenOnLoad ;
2012-10-05 21:04:46 +00:00
2013-11-27 23:35:32 +00:00
private int _autoDumpLength ;
2013-12-29 23:35:42 +00:00
private readonly bool _autoCloseOnDump ;
2013-11-27 23:35:32 +00:00
private int _lastOpenRomFilter ;
2013-04-27 02:02:37 +00:00
2014-12-14 01:43:46 +00:00
//chrome is never shown, even in windowed mode
private readonly bool _chromeless ;
2014-02-17 09:20:08 +00:00
// Resources
Bitmap StatusBarDiskLightOnImage , StatusBarDiskLightOffImage ;
2014-08-23 01:18:59 +00:00
Bitmap LinkCableOn , LinkCableOff ;
2013-04-27 02:02:37 +00:00
2015-02-22 03:45:00 +00:00
// input state which has been destined for game controller inputs are coalesced here
// public static ControllerInputCoalescer ControllerInputCoalescer = new ControllerInputCoalescer();
// input state which has been destined for client hotkey consumption are colesced here
private readonly InputCoalescer HotkeyCoalescer = new InputCoalescer ( ) ;
2015-02-22 03:53:07 +00:00
public PresentationPanel PresentationPanel { get ; set ; }
2013-11-03 02:51:21 +00:00
#endregion
2013-04-27 02:02:37 +00:00
2013-11-03 02:51:21 +00:00
#region Private methods
2013-12-20 22:05:56 +00:00
2014-07-21 20:34:53 +00:00
private void SetWindowText ( )
{
2014-11-30 14:18:44 +00:00
string str = string . Empty ;
2014-10-17 00:28:21 +00:00
2014-09-14 00:51:30 +00:00
if ( _inResizeLoop )
2014-07-21 20:34:53 +00:00
{
2015-02-22 03:53:07 +00:00
var size = PresentationPanel . NativeSize ;
2015-10-21 09:47:15 +00:00
float AR = ( float ) size . Width / size . Height ;
str = str + string . Format ( "({0}x{1})={2} - " , size . Width , size . Height , AR ) ;
2014-07-21 20:34:53 +00:00
}
2015-08-18 04:26:19 +00:00
//we need to display FPS somewhere, in this case
if ( Global . Config . DispSpeedupFeatures = = 0 )
{
2016-09-29 07:04:39 +00:00
str = str + string . Format ( "({0:0} fps) -" , _runloopDisplayFps ) ;
2015-08-18 04:26:19 +00:00
}
2016-11-13 00:49:03 +00:00
if ( ! string . IsNullOrEmpty ( VersionInfo . CustomBuildString ) )
str + = VersionInfo . CustomBuildString + " " ;
2016-12-04 17:19:34 +00:00
if ( Emulator . IsNull ( ) )
2014-09-14 00:51:30 +00:00
{
str = str + "BizHawk" + ( VersionInfo . DeveloperBuild ? " (interim) " : string . Empty ) ;
}
else
{
str = str + Global . SystemInfo . DisplayName ;
2014-07-21 20:34:53 +00:00
2014-09-19 00:15:27 +00:00
if ( VersionInfo . DeveloperBuild )
{
str + = " (interim)" ;
}
2014-07-21 20:34:53 +00:00
2014-09-19 00:15:27 +00:00
if ( Global . MovieSession . Movie . IsActive )
{
str = str + " - " + Global . Game . Name + " - " + Path . GetFileName ( Global . MovieSession . Movie . Filename ) ;
}
else
{
str = str + " - " + Global . Game . Name ;
}
2014-07-21 20:34:53 +00:00
}
2014-09-14 00:51:30 +00:00
2014-12-14 01:43:46 +00:00
if ( ! Global . Config . DispChrome_CaptionWindowed | | _chromeless )
str = "" ;
2014-09-14 00:51:30 +00:00
Text = str ;
2014-07-21 20:34:53 +00:00
}
2014-01-21 00:36:22 +00:00
private void ClearAutohold ( )
{
ClearHolds ( ) ;
GlobalWin . OSD . AddMessage ( "Autohold keys cleared" ) ;
}
2013-11-27 23:35:32 +00:00
private static void UpdateToolsLoadstate ( )
2013-11-03 02:51:21 +00:00
{
2013-11-03 16:07:58 +00:00
if ( GlobalWin . Tools . Has < SNESGraphicsDebugger > ( ) )
2013-11-03 02:51:21 +00:00
{
2013-11-03 16:07:58 +00:00
GlobalWin . Tools . SNESGraphicsDebugger . UpdateToolsLoadstate ( ) ;
2013-11-03 02:51:21 +00:00
}
}
2011-08-09 00:51:46 +00:00
2013-11-03 02:51:21 +00:00
private void UpdateToolsAfter ( bool fromLua = false )
{
2013-11-27 23:35:32 +00:00
GlobalWin . Tools . UpdateToolsAfter ( fromLua ) ;
2014-08-23 01:18:59 +00:00
HandleToggleLightAndLink ( ) ;
2013-11-03 02:51:21 +00:00
}
2013-04-24 22:09:11 +00:00
2014-04-15 22:10:39 +00:00
public void UpdateDumpIcon ( )
2011-07-10 15:36:41 +00:00
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . Blank ;
2013-12-20 22:05:56 +00:00
DumpStatusButton . ToolTipText = string . Empty ;
2011-07-10 21:00:28 +00:00
2016-12-04 17:19:34 +00:00
if ( Emulator . IsNull ( ) )
2013-12-20 22:05:56 +00:00
{
return ;
}
else if ( Global . Game = = null )
{
return ;
}
2011-07-10 21:00:28 +00:00
2011-08-04 03:20:54 +00:00
var status = Global . Game . Status ;
2013-04-16 00:19:31 +00:00
string annotation ;
2011-07-10 21:00:28 +00:00
if ( status = = RomStatus . BadDump )
2011-07-10 15:36:41 +00:00
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . ExclamationRed ;
2011-07-10 21:00:28 +00:00
annotation = "Warning: Bad ROM Dump" ;
}
else if ( status = = RomStatus . Overdump )
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . ExclamationRed ;
2011-07-10 21:00:28 +00:00
annotation = "Warning: Overdump" ;
}
else if ( status = = RomStatus . NotInDatabase )
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . RetroQuestion ;
2011-07-10 21:00:28 +00:00
annotation = "Warning: Unknown ROM" ;
}
else if ( status = = RomStatus . TranslatedRom )
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . Translation ;
2011-07-10 21:00:28 +00:00
annotation = "Translated ROM" ;
}
else if ( status = = RomStatus . Homebrew )
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . HomeBrew ;
2011-07-10 21:00:28 +00:00
annotation = "Homebrew ROM" ;
}
else if ( Global . Game . Status = = RomStatus . Hack )
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . Hack ;
2011-07-10 21:00:28 +00:00
annotation = "Hacked ROM" ;
2011-07-10 15:36:41 +00:00
}
2012-04-16 08:18:41 +00:00
else if ( Global . Game . Status = = RomStatus . Unknown )
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . Hack ;
2012-04-16 08:18:41 +00:00
annotation = "Warning: ROM of Unknown Character" ;
}
2011-07-10 15:36:41 +00:00
else
{
2013-10-27 15:53:37 +00:00
DumpStatusButton . Image = Properties . Resources . GreenCheck ;
2011-07-10 21:00:28 +00:00
annotation = "Verified good dump" ;
2011-07-10 15:36:41 +00:00
}
2013-12-20 22:05:56 +00:00
2016-12-04 17:19:34 +00:00
if ( ! string . IsNullOrEmpty ( Emulator . CoreComm . RomStatusAnnotation ) )
2013-12-20 22:05:56 +00:00
{
2016-12-04 17:19:34 +00:00
annotation = Emulator . CoreComm . RomStatusAnnotation ;
2013-12-20 22:05:56 +00:00
}
2011-07-10 21:00:28 +00:00
2013-10-27 15:53:37 +00:00
DumpStatusButton . ToolTipText = annotation ;
2011-07-10 15:36:41 +00:00
}
2016-12-04 17:19:34 +00:00
private void LoadSaveRam ( )
2011-02-20 08:40:22 +00:00
{
2016-12-04 17:19:34 +00:00
if ( Emulator . HasSaveRam ( ) )
2011-08-09 00:51:46 +00:00
{
2014-11-30 15:22:08 +00:00
try // zero says: this is sort of sketchy... but this is no time for rearchitecting
2012-11-24 02:25:47 +00:00
{
2014-11-30 15:22:08 +00:00
byte [ ] sram ;
// GBA meteor core might not know how big the saveram ought to be, so just send it the whole file
// GBA vba-next core will try to eat anything, regardless of size
2016-12-04 17:19:34 +00:00
if ( Emulator is GBA | | Emulator is VBANext | | Emulator is MGBAHawk )
2014-02-06 22:08:01 +00:00
{
2014-11-30 15:22:08 +00:00
sram = File . ReadAllBytes ( PathManager . SaveRamPath ( Global . Game ) ) ;
2014-02-06 22:08:01 +00:00
}
2014-11-30 15:22:08 +00:00
else
2013-12-20 22:05:56 +00:00
{
2016-12-04 17:19:34 +00:00
var oldram = Emulator . AsSaveRam ( ) . CloneSaveRam ( ) ;
2014-11-30 15:22:08 +00:00
if ( oldram = = null )
{
// we're eating this one now. the possible negative consequence is that a user could lose
// their saveram and not know why
// MessageBox.Show("Error: tried to load saveram, but core would not accept it?");
return ;
}
// why do we silently truncate\pad here instead of warning\erroring?
sram = new byte [ oldram . Length ] ;
using ( var reader = new BinaryReader (
new FileStream ( PathManager . SaveRamPath ( Global . Game ) , FileMode . Open , FileAccess . Read ) ) )
{
reader . Read ( sram , 0 , sram . Length ) ;
}
2013-12-20 22:05:56 +00:00
}
2016-12-04 17:19:34 +00:00
Emulator . AsSaveRam ( ) . StoreSaveRam ( sram ) ;
2014-11-30 15:22:08 +00:00
}
catch ( IOException )
{
GlobalWin . OSD . AddMessage ( "An error occurred while loading Sram" ) ;
}
2013-12-20 22:05:56 +00:00
}
2011-02-20 08:40:22 +00:00
}
2016-12-04 17:19:34 +00:00
private void SaveRam ( )
2011-08-09 00:51:46 +00:00
{
2016-12-04 17:19:34 +00:00
if ( Emulator . HasSaveRam ( ) )
2012-09-29 15:32:44 +00:00
{
2014-11-30 15:22:08 +00:00
var path = PathManager . SaveRamPath ( Global . Game ) ;
var f = new FileInfo ( path ) ;
if ( f . Directory ! = null & & f . Directory . Exists = = false )
2013-11-27 23:35:32 +00:00
{
2014-11-30 15:22:08 +00:00
f . Directory . Create ( ) ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2014-11-30 15:22:08 +00:00
// Make backup first
if ( Global . Config . BackupSaveram & & f . Exists )
{
var backup = path + ".bak" ;
var backupFile = new FileInfo ( backup ) ;
if ( backupFile . Exists )
{
backupFile . Delete ( ) ;
}
f . CopyTo ( backup ) ;
}
2012-09-29 15:32:44 +00:00
2014-11-30 15:22:08 +00:00
var writer = new BinaryWriter ( new FileStream ( path , FileMode . Create , FileAccess . Write ) ) ;
2016-12-04 17:19:34 +00:00
var saveram = Emulator . AsSaveRam ( ) . CloneSaveRam ( ) ;
2012-09-14 22:28:38 +00:00
2014-11-30 15:22:08 +00:00
writer . Write ( saveram , 0 , saveram . Length ) ;
writer . Close ( ) ;
}
2011-08-09 00:51:46 +00:00
}
2011-08-04 03:20:54 +00:00
2013-11-03 02:51:21 +00:00
private void RewireSound ( )
2011-07-24 23:14:16 +00:00
{
2013-11-27 23:35:32 +00:00
if ( _dumpProxy ! = null )
2011-07-24 23:14:16 +00:00
{
2013-11-03 02:51:21 +00:00
// we're video dumping, so async mode only and use the DumpProxy.
// note that the avi dumper has already rewired the emulator itself in this case.
2016-12-12 03:37:28 +00:00
GlobalWin . Sound . SetSyncInputPin ( _dumpProxy ) ;
2013-11-03 02:51:21 +00:00
}
2016-12-11 23:35:42 +00:00
else if ( Global . Config . SoundThrottle | | ! _currentSoundProvider . CanProvideAsync )
2013-11-03 02:51:21 +00:00
{
2016-12-11 20:01:42 +00:00
_currentSoundProvider . SetSyncMode ( SyncSoundMode . Sync ) ;
2016-12-11 17:14:42 +00:00
GlobalWin . Sound . SetSyncInputPin ( _currentSoundProvider ) ;
2013-11-03 02:51:21 +00:00
}
2016-12-11 20:01:42 +00:00
else
{
_currentSoundProvider . SetSyncMode ( SyncSoundMode . Async ) ;
GlobalWin . Sound . SetAsyncInputPin ( _currentSoundProvider ) ;
}
2011-07-24 23:14:16 +00:00
}
2013-11-03 02:51:21 +00:00
private void HandlePlatformMenus ( )
2014-10-19 01:22:47 +00:00
{
var system = string . Empty ;
if ( ! Global . Game . IsNullInstance )
{
//New Code
2014-08-27 18:15:02 +00:00
//We use SystemID as that has the system we are playing on.
2016-12-04 17:19:34 +00:00
system = Emulator . SystemId ;
2014-10-19 01:22:47 +00:00
//Old Code below.
//system = Global.Game.System;
}
TI83SubMenu . Visible = false ;
NESSubMenu . Visible = false ;
PCESubMenu . Visible = false ;
SMSSubMenu . Visible = false ;
GBSubMenu . Visible = false ;
GBASubMenu . Visible = false ;
AtariSubMenu . Visible = false ;
SNESSubMenu . Visible = false ;
2014-12-11 20:31:55 +00:00
PSXSubMenu . Visible = false ;
2014-10-19 01:22:47 +00:00
ColecoSubMenu . Visible = false ;
N64SubMenu . Visible = false ;
SaturnSubMenu . Visible = false ;
DGBSubMenu . Visible = false ;
GenesisSubMenu . Visible = false ;
wonderSwanToolStripMenuItem . Visible = false ;
2015-04-13 00:46:11 +00:00
AppleSubMenu . Visible = false ;
2015-10-10 16:20:59 +00:00
C64SubMenu . Visible = false ;
2016-12-03 23:44:25 +00:00
IntvSubMenu . Visible = false ;
2014-10-19 01:22:47 +00:00
switch ( system )
{
case "GEN" :
GenesisSubMenu . Visible = true ;
break ;
case "TI83" :
TI83SubMenu . Visible = true ;
break ;
case "NES" :
NESSubMenu . Visible = true ;
break ;
case "PCE" :
case "PCECD" :
case "SGX" :
PCESubMenu . Visible = true ;
break ;
case "SMS" :
SMSSubMenu . Text = "&SMS" ;
SMSSubMenu . Visible = true ;
break ;
case "SG" :
SMSSubMenu . Text = "&SG" ;
SMSSubMenu . Visible = true ;
break ;
case "GG" :
SMSSubMenu . Text = "&GG" ;
SMSSubMenu . Visible = true ;
break ;
case "GB" :
case "GBC" :
GBSubMenu . Visible = true ;
break ;
case "GBA" :
GBASubMenu . Visible = true ;
break ;
case "A26" :
AtariSubMenu . Visible = true ;
break ;
2014-12-11 20:31:55 +00:00
case "PSX" :
PSXSubMenu . Visible = true ;
break ;
2014-10-19 01:22:47 +00:00
case "SNES" :
case "SGB" :
// TODO: fix SNES9x here
2016-12-04 17:19:34 +00:00
if ( Emulator is LibsnesCore )
2014-10-19 01:22:47 +00:00
{
2016-12-04 17:19:34 +00:00
if ( ( Emulator as LibsnesCore ) . IsSGB )
2014-10-19 01:22:47 +00:00
{
SNESSubMenu . Text = "&SGB" ;
}
else
{
SNESSubMenu . Text = "&SNES" ;
}
SNESSubMenu . Visible = true ;
}
else
{
SNESSubMenu . Visible = false ;
}
break ;
case "Coleco" :
ColecoSubMenu . Visible = true ;
break ;
case "N64" :
N64SubMenu . Visible = true ;
break ;
case "SAT" :
SaturnSubMenu . Visible = true ;
break ;
case "DGB" :
DGBSubMenu . Visible = true ;
break ;
case "WSWAN" :
wonderSwanToolStripMenuItem . Visible = true ;
break ;
2015-04-13 00:46:11 +00:00
case "AppleII" :
AppleSubMenu . Visible = true ;
break ;
2015-10-10 16:20:59 +00:00
case "C64" :
C64SubMenu . Visible = true ;
break ;
2016-12-03 23:44:25 +00:00
case "INTV" :
IntvSubMenu . Visible = true ;
break ;
2014-10-19 01:22:47 +00:00
}
}
2013-10-09 20:43:13 +00:00
2016-12-04 17:19:34 +00:00
private void InitControls ( )
2013-11-03 02:51:21 +00:00
{
var controls = new Controller (
new ControllerDefinition
{
Name = "Emulator Frontend Controls" ,
BoolButtons = Global . Config . HotkeyBindings . Select ( x = > x . DisplayName ) . ToList ( )
} ) ;
2013-08-04 20:32:50 +00:00
2013-11-03 02:51:21 +00:00
foreach ( var b in Global . Config . HotkeyBindings )
{
controls . BindMulti ( b . DisplayName , b . Bindings ) ;
2013-08-04 16:47:54 +00:00
}
2011-07-10 07:39:40 +00:00
2013-11-03 16:47:21 +00:00
Global . ClientControls = controls ;
2016-12-04 17:19:34 +00:00
Global . AutofireNullControls = new AutofireController ( NullEmulator . NullController , Emulator ) ;
2013-11-03 02:51:21 +00:00
2011-06-11 12:54:26 +00:00
}
2013-11-03 02:51:21 +00:00
private void LoadMoviesFromRecent ( string path )
2011-02-20 08:40:22 +00:00
{
2014-06-12 21:45:47 +00:00
if ( File . Exists ( path ) )
2012-03-16 15:27:45 +00:00
{
2014-06-12 21:45:47 +00:00
var movie = MovieService . Get ( path ) ;
Global . MovieSession . ReadOnly = true ;
StartNewMovie ( movie , false ) ;
2012-03-16 15:27:45 +00:00
}
2013-11-03 02:51:21 +00:00
else
2011-02-20 08:40:22 +00:00
{
2014-07-28 01:51:11 +00:00
Global . Config . RecentMovies . HandleLoadError ( path ) ;
2011-02-20 08:40:22 +00:00
}
2013-11-03 02:51:21 +00:00
}
private void LoadRomFromRecent ( string rom )
{
2015-11-06 14:31:50 +00:00
var ioa = OpenAdvancedSerializer . ParseWithLegacy ( rom ) ;
LoadRomArgs args = new LoadRomArgs ( )
{
OpenAdvanced = ioa
} ;
//if(ioa is this or that) - for more complex behaviour
2016-08-18 01:23:56 +00:00
string romPath = ioa . SimplePath ;
2015-11-06 14:31:50 +00:00
2016-08-18 01:23:56 +00:00
if ( ! LoadRom ( romPath , args ) )
2011-02-20 08:40:22 +00:00
{
2016-08-18 01:23:56 +00:00
Global . Config . RecentRoms . HandleLoadError ( romPath , rom ) ;
2011-02-20 08:40:22 +00:00
}
2013-11-03 02:51:21 +00:00
}
2012-03-16 15:27:45 +00:00
2013-11-03 02:51:21 +00:00
private void SetPauseStatusbarIcon ( )
{
2014-08-01 02:16:56 +00:00
if ( IsTurboSeeking )
2014-07-27 19:07:13 +00:00
{
PauseStatusButton . Image = Properties . Resources . Lightning ;
PauseStatusButton . Visible = true ;
PauseStatusButton . ToolTipText = "Emulator is turbo seeking to frame " + PauseOnFrame . Value + " click to stop seek" ;
}
else if ( PauseOnFrame . HasValue )
{
PauseStatusButton . Image = Properties . Resources . YellowRight ;
PauseStatusButton . Visible = true ;
PauseStatusButton . ToolTipText = "Emulator is playing to frame " + PauseOnFrame . Value + " click to stop seek" ;
}
else if ( EmulatorPaused )
2012-03-16 15:27:45 +00:00
{
2013-11-03 02:51:21 +00:00
PauseStatusButton . Image = Properties . Resources . Pause ;
PauseStatusButton . Visible = true ;
PauseStatusButton . ToolTipText = "Emulator Paused" ;
}
else
{
PauseStatusButton . Image = Properties . Resources . Blank ;
PauseStatusButton . Visible = false ;
2014-05-12 20:51:09 +00:00
PauseStatusButton . ToolTipText = string . Empty ;
2012-03-16 15:27:45 +00:00
}
2013-11-03 02:51:21 +00:00
}
2011-02-20 08:40:22 +00:00
2013-11-03 02:51:21 +00:00
private void SyncThrottle ( )
{
2015-01-25 18:34:53 +00:00
// "unthrottled" = throttle was turned off with "Toggle Throttle" hotkey
// "turbo" = throttle is off due to the "Turbo" hotkey being held
// They are basically the same thing but one is a toggle and the other requires a
// hotkey to be held. There is however slightly different behavior in that turbo
// skips outputting the audio. There's also a third way which is when no throttle
// method is selected, but the clock throttle determines that by itself and
// everything appears normal here.
2014-10-11 09:01:50 +00:00
2015-01-12 05:30:27 +00:00
var rewind = Global . Rewinder . RewindActive & & ( Global . ClientControls [ "Rewind" ] | | PressRewind ) ;
2015-01-13 04:21:32 +00:00
var fastForward = Global . ClientControls [ "Fast Forward" ] | | FastForward ;
2015-01-25 18:34:53 +00:00
var turbo = IsTurboing ;
2015-01-12 15:09:27 +00:00
2015-01-13 04:21:32 +00:00
int speedPercent = fastForward ? Global . Config . SpeedPercentAlternate : Global . Config . SpeedPercent ;
2015-01-12 15:09:27 +00:00
if ( rewind )
{
2015-01-25 18:34:53 +00:00
speedPercent = Math . Max ( speedPercent * Global . Config . RewindSpeedMultiplier / Global . Rewinder . RewindFrequency , 5 ) ;
2015-01-12 15:09:27 +00:00
}
2015-01-25 18:34:53 +00:00
Global . DisableSecondaryThrottling = _unthrottled | | turbo | | fastForward | | rewind ;
2013-11-03 02:51:21 +00:00
// realtime throttle is never going to be so exact that using a double here is wrong
2016-12-04 17:19:34 +00:00
_throttle . SetCoreFps ( Emulator . CoreComm . VsyncRate ) ;
2015-01-15 15:56:23 +00:00
_throttle . signal_paused = EmulatorPaused ;
2015-01-25 18:34:53 +00:00
_throttle . signal_unthrottle = _unthrottled | | turbo ;
2016-03-26 17:39:18 +00:00
//zero 26-mar-2016 - vsync and vsync throttle here both is odd, but see comments elsewhere about triple buffering
2015-01-13 04:21:32 +00:00
_throttle . signal_overrideSecondaryThrottle = ( fastForward | | rewind ) & & ( Global . Config . SoundThrottle | | Global . Config . VSyncThrottle | | Global . Config . VSync ) ;
2015-01-12 15:09:27 +00:00
_throttle . SetSpeedPercent ( speedPercent ) ;
2011-02-20 08:40:22 +00:00
}
2013-11-03 02:51:21 +00:00
private void SetSpeedPercentAlternate ( int value )
2011-07-09 00:26:23 +00:00
{
2013-11-03 02:51:21 +00:00
Global . Config . SpeedPercentAlternate = value ;
SyncThrottle ( ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "Alternate Speed: " + value + "%" ) ;
2012-09-22 05:03:52 +00:00
}
2013-11-03 02:51:21 +00:00
private void SetSpeedPercent ( int value )
2012-09-22 05:03:52 +00:00
{
2013-11-03 02:51:21 +00:00
Global . Config . SpeedPercent = value ;
SyncThrottle ( ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "Speed: " + value + "%" ) ;
2011-07-09 00:26:23 +00:00
}
2013-11-03 02:51:21 +00:00
private void Shutdown ( )
2012-05-28 01:29:43 +00:00
{
2013-11-27 23:35:32 +00:00
if ( _currAviWriter ! = null )
2013-09-07 01:38:24 +00:00
{
2013-11-27 23:35:32 +00:00
_currAviWriter . CloseFile ( ) ;
_currAviWriter = null ;
2013-09-07 01:38:24 +00:00
}
2013-11-03 02:51:21 +00:00
}
2012-10-13 12:44:52 +00:00
2013-11-27 23:35:32 +00:00
private static void CheckMessages ( )
2013-11-03 02:51:21 +00:00
{
Application . DoEvents ( ) ;
if ( ActiveForm ! = null )
2013-11-27 23:35:32 +00:00
{
2013-11-03 02:51:21 +00:00
ScreenSaver . ResetTimerPeriodically ( ) ;
2013-11-27 23:35:32 +00:00
}
2012-05-28 01:29:43 +00:00
}
2012-05-28 00:44:27 +00:00
2015-07-24 20:59:53 +00:00
void AutohideCursor ( bool hide )
{
if ( hide & & ! _cursorHidden )
{
if ( _blankCursor = = null )
{
var ms = new System . IO . MemoryStream ( BizHawk . Client . EmuHawk . Properties . Resources . BlankCursor ) ;
_blankCursor = new Cursor ( ms ) ;
}
PresentationPanel . Control . Cursor = _blankCursor ;
_cursorHidden = true ;
}
else if ( ! hide & & _cursorHidden )
{
PresentationPanel . Control . Cursor = Cursors . Default ;
timerMouseIdle . Stop ( ) ;
timerMouseIdle . Start ( ) ;
_cursorHidden = false ;
}
}
2016-12-04 17:19:34 +00:00
private BitmapBuffer MakeScreenshotImage ( )
2011-06-11 12:54:26 +00:00
{
2016-12-07 19:21:18 +00:00
return GlobalWin . DisplayManager . RenderVideoProvider ( _currentVideoProvider ) ;
2011-06-11 12:54:26 +00:00
}
2011-05-22 19:52:49 +00:00
2015-09-08 20:56:20 +00:00
private void SaveSlotSelectedMessage ( )
2011-02-20 08:40:22 +00:00
{
2015-09-08 20:56:20 +00:00
int slot = Global . Config . SaveSlot ;
string emptypart = _stateSlots . HasSlot ( slot ) ? "" : " (empty)" ;
string message = string . Format ( "Slot {0}{1} selected." , slot , emptypart ) ;
GlobalWin . OSD . AddMessage ( message ) ;
2011-02-20 08:40:22 +00:00
}
private void Render ( )
{
2016-09-29 07:57:32 +00:00
if ( Global . Config . DispSpeedupFeatures = = 0 )
{
return ;
}
2014-05-18 02:11:17 +00:00
//private Size _lastVideoSize = new Size(-1, -1), _lastVirtualSize = new Size(-1, -1);
2016-12-07 19:21:18 +00:00
var video = _currentVideoProvider ;
2014-05-19 12:57:02 +00:00
//bool change = false;
2015-11-06 14:31:50 +00:00
Size currVideoSize = new Size ( video . BufferWidth , video . BufferHeight ) ;
Size currVirtualSize = new Size ( video . VirtualWidth , video . VirtualHeight ) ;
2014-05-18 02:11:17 +00:00
if ( currVideoSize ! = _lastVideoSize | | currVirtualSize ! = _lastVirtualSize )
2011-02-20 08:40:22 +00:00
{
2014-05-18 02:11:17 +00:00
_lastVideoSize = currVideoSize ;
_lastVirtualSize = currVirtualSize ;
2011-02-20 08:40:22 +00:00
FrameBufferResized ( ) ;
}
2015-01-14 22:37:37 +00:00
GlobalWin . DisplayManager . UpdateSource ( video ) ;
2011-02-20 08:40:22 +00:00
}
2013-12-20 22:05:56 +00:00
// sends a simulation of a plain alt key keystroke
2013-11-03 02:51:21 +00:00
private void SendPlainAltKey ( int lparam )
2011-07-10 19:50:59 +00:00
{
2013-11-27 23:35:32 +00:00
var m = new Message { WParam = new IntPtr ( 0xF100 ) , LParam = new IntPtr ( lparam ) , Msg = 0x0112 , HWnd = Handle } ;
2011-07-10 19:50:59 +00:00
base . WndProc ( ref m ) ;
}
2013-12-20 22:05:56 +00:00
// sends an alt+mnemonic combination
2013-11-03 02:51:21 +00:00
private void SendAltKeyChar ( char c )
2011-07-10 19:50:59 +00:00
{
2013-10-27 07:54:00 +00:00
typeof ( ToolStrip ) . InvokeMember ( "ProcessMnemonicInternal" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . InvokeMethod | System . Reflection . BindingFlags . Instance , null , MainformMenu , new object [ ] { c } ) ;
2011-07-10 19:50:59 +00:00
}
2015-11-08 01:59:10 +00:00
public static string FormatFilter ( params string [ ] args )
2011-07-24 06:45:05 +00:00
{
var sb = new StringBuilder ( ) ;
2013-12-20 22:05:56 +00:00
if ( args . Length % 2 ! = 0 )
{
throw new ArgumentException ( ) ;
}
2013-11-27 23:35:32 +00:00
var num = args . Length / 2 ;
2011-07-24 06:45:05 +00:00
for ( int i = 0 ; i < num ; i + + )
{
sb . AppendFormat ( "{0} ({1})|{1}" , args [ i * 2 ] , args [ i * 2 + 1 ] ) ;
2013-12-20 22:05:56 +00:00
if ( i ! = num - 1 )
{
sb . Append ( '|' ) ;
}
2011-07-24 06:45:05 +00:00
}
2013-12-20 22:05:56 +00:00
2014-06-22 16:41:39 +00:00
var str = sb . ToString ( ) . Replace ( "%ARCH%" , "*.zip;*.rar;*.7z;*.gz" ) ;
2011-07-24 06:45:05 +00:00
str = str . Replace ( ";" , "; " ) ;
return str ;
}
2015-04-19 22:34:08 +00:00
public static string RomFilter
2011-06-11 12:54:26 +00:00
{
2015-04-19 22:34:08 +00:00
get
2012-03-18 00:00:47 +00:00
{
2015-04-19 22:34:08 +00:00
if ( VersionInfo . DeveloperBuild )
{
return FormatFilter (
2016-11-13 14:25:06 +00:00
"Rom Files" , "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.col;.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.psf;*.minipsf;*.nsf;*.int;%ARCH%" ,
2015-07-21 04:11:00 +00:00
"Music Files" , "*.psf;*.minipsf;*.sid;*.nsf" ,
2015-04-19 22:34:08 +00:00
"Disc Images" , "*.cue;*.ccd;*.m3u" ,
2015-08-17 20:27:40 +00:00
"NES" , "*.nes;*.fds;*.unf;*.nsf;%ARCH%" ,
2015-04-19 22:34:08 +00:00
"Super NES" , "*.smc;*.sfc;*.xml;%ARCH%" ,
"Master System" , "*.sms;*.gg;*.sg;%ARCH%" ,
"PC Engine" , "*.pce;*.sgx;*.cue;*.ccd;%ARCH%" ,
"TI-83" , "*.rom;%ARCH%" ,
"Archive Files" , "%ARCH%" ,
"Savestate" , "*.state" ,
"Atari 2600" , "*.a26;*.bin;%ARCH%" ,
"Atari 7800" , "*.a78;*.bin;%ARCH%" ,
"Atari Lynx" , "*.lnx;%ARCH%" ,
"Genesis" , "*.gen;*.smd;*.bin;*.md;*.cue;*.ccd;%ARCH%" ,
"Gameboy" , "*.gb;*.gbc;*.sgb;%ARCH%" ,
"Gameboy Advance" , "*.gba;%ARCH%" ,
"Colecovision" , "*.col;%ARCH%" ,
"Intellivision (very experimental)" , "*.int;*.bin;*.rom;%ARCH%" ,
2015-07-23 15:23:39 +00:00
"PlayStation" , "*.cue;*.ccd;*.m3u" ,
2015-04-19 22:34:08 +00:00
"PSX Executables (experimental)" , "*.exe" ,
2015-07-21 04:11:00 +00:00
"PSF Playstation Sound File" , "*.psf;*.minipsf" ,
2015-09-27 23:30:58 +00:00
"Commodore 64 (experimental)" , "*.prg; *.d64, *.g64; *.crt; *.tap;%ARCH%" ,
2015-04-19 22:34:08 +00:00
"SID Commodore 64 Music File" , "*.sid;%ARCH%" ,
"Nintendo 64" , "*.z64;*.v64;*.n64" ,
"WonderSwan" , "*.ws;*.wsc;%ARCH%" ,
2015-05-28 00:16:08 +00:00
"Apple II" , "*.dsk;*.do;*.po;%ARCH%" ,
2015-04-19 22:34:08 +00:00
"All Files" , "*.*" ) ;
}
return FormatFilter (
2015-08-17 20:27:40 +00:00
"Rom Files" , "*.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;%ARCH%" ,
2014-12-14 10:36:03 +00:00
"Disc Images" , "*.cue;*.ccd;*.m3u" ,
2015-08-17 20:27:40 +00:00
"NES" , "*.nes;*.fds;*.unf;*.nsf;%ARCH%" ,
2013-04-24 22:09:11 +00:00
"Super NES" , "*.smc;*.sfc;*.xml;%ARCH%" ,
2015-07-23 15:23:39 +00:00
"PlayStation" , "*.cue;*.ccd;*.m3u" ,
"PSF Playstation Sound File" , "*.psf;*.minipsf" ,
2013-07-28 22:45:19 +00:00
"Nintendo 64" , "*.z64;*.v64;*.n64" ,
2013-03-09 18:41:23 +00:00
"Gameboy" , "*.gb;*.gbc;*.sgb;%ARCH%" ,
2014-08-27 01:54:39 +00:00
"Gameboy Advance" , "*.gba;%ARCH%" ,
2012-03-18 00:00:47 +00:00
"Master System" , "*.sms;*.gg;*.sg;%ARCH%" ,
2014-12-04 05:40:10 +00:00
"PC Engine" , "*.pce;*.sgx;*.cue;*.ccd;%ARCH%" ,
2012-10-20 13:40:58 +00:00
"Atari 2600" , "*.a26;%ARCH%" ,
2012-12-23 18:55:05 +00:00
"Atari 7800" , "*.a78;%ARCH%" ,
2014-11-17 22:23:06 +00:00
"Atari Lynx" , "*.lnx;%ARCH%" ,
2012-11-18 02:51:39 +00:00
"Colecovision" , "*.col;%ARCH%" ,
2012-03-18 00:00:47 +00:00
"TI-83" , "*.rom;%ARCH%" ,
"Archive Files" , "%ARCH%" ,
"Savestate" , "*.state" ,
2014-12-04 05:40:10 +00:00
"Genesis" , "*.gen;*.md;*.smd;*.bin;*.cue;*.ccd;%ARCH%" ,
2014-08-27 01:54:39 +00:00
"WonderSwan" , "*.ws;*.wsc;%ARCH%" ,
2015-06-10 22:32:47 +00:00
"Apple II" , "*.dsk;*.do;*.po;%ARCH%" ,
2012-03-18 00:00:47 +00:00
"All Files" , "*.*" ) ;
}
2015-04-19 22:34:08 +00:00
}
2013-09-07 01:38:24 +00:00
2015-04-19 22:34:08 +00:00
private void OpenRom ( )
{
var ofd = new OpenFileDialog
{
2016-12-04 17:19:34 +00:00
InitialDirectory = PathManager . GetRomsPath ( Emulator . SystemId ) ,
2015-04-19 22:34:08 +00:00
Filter = RomFilter ,
RestoreDirectory = false ,
FilterIndex = _lastOpenRomFilter
} ;
2013-09-07 01:38:24 +00:00
2013-11-28 22:39:00 +00:00
var result = ofd . ShowHawkDialog ( ) ;
2011-06-11 12:54:26 +00:00
if ( result ! = DialogResult . OK )
2013-11-28 22:39:00 +00:00
{
2011-06-11 12:54:26 +00:00
return ;
2013-11-28 22:39:00 +00:00
}
2011-06-11 12:54:26 +00:00
var file = new FileInfo ( ofd . FileName ) ;
Global . Config . LastRomPath = file . DirectoryName ;
2013-11-27 23:35:32 +00:00
_lastOpenRomFilter = ofd . FilterIndex ;
2015-11-06 14:31:50 +00:00
var lra = new LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom { Path = file . FullName } } ;
LoadRom ( file . FullName , lra ) ;
2011-06-11 12:54:26 +00:00
}
2013-12-29 23:35:42 +00:00
private void CoreSyncSettings ( object sender , RomLoader . SettingsLoadArgs e )
2013-12-24 23:32:43 +00:00
{
2014-12-08 22:53:09 +00:00
if ( Global . MovieSession . QueuedMovie ! = null )
2014-08-02 17:49:10 +00:00
{
2014-12-08 22:53:09 +00:00
if ( ! string . IsNullOrWhiteSpace ( Global . MovieSession . QueuedMovie . SyncSettingsJson ) )
{
e . Settings = ConfigService . LoadWithType ( Global . MovieSession . QueuedMovie . SyncSettingsJson ) ;
}
else
{
2015-06-21 00:50:34 +00:00
e . Settings = Global . Config . GetCoreSyncSettings ( e . Core ) ;
// adelikat: only show this nag if the core actually has sync settings, not all cores do
2015-08-01 15:13:22 +00:00
if ( e . Settings ! = null & & ! _supressSyncSettingsWarning )
2015-06-21 00:50:34 +00:00
{
MessageBox . Show (
2014-12-08 22:53:09 +00:00
"No sync settings found, using currently configured settings for this core." ,
"No sync settings found" ,
MessageBoxButtons . OK ,
MessageBoxIcon . Warning
) ;
2015-06-21 00:50:34 +00:00
}
2014-12-08 22:53:09 +00:00
}
2014-08-02 17:49:10 +00:00
}
else
{
e . Settings = Global . Config . GetCoreSyncSettings ( e . Core ) ;
}
2013-12-26 20:19:28 +00:00
}
2013-12-29 23:35:42 +00:00
private static void CoreSettings ( object sender , RomLoader . SettingsLoadArgs e )
2013-12-26 20:19:28 +00:00
{
e . Settings = Global . Config . GetCoreSettings ( e . Core ) ;
2013-12-24 23:32:43 +00:00
}
2013-12-22 20:41:21 +00:00
/// <summary>
/// send core settings to emu, setting reboot flag if needed
/// </summary>
2013-12-24 01:06:17 +00:00
public void PutCoreSettings ( object o )
2013-12-22 20:41:21 +00:00
{
2016-12-04 17:19:34 +00:00
var settable = new SettingsAdapter ( Emulator ) ;
2014-12-17 01:23:24 +00:00
if ( settable . HasSettings & & settable . PutSettings ( o ) )
2013-12-29 23:35:42 +00:00
{
2013-12-22 20:41:21 +00:00
FlagNeedsReboot ( ) ;
2013-12-29 23:35:42 +00:00
}
2013-12-22 20:41:21 +00:00
}
2013-12-23 02:51:41 +00:00
/// <summary>
/// send core sync settings to emu, setting reboot flag if needed
/// </summary>
2013-12-23 23:03:12 +00:00
public void PutCoreSyncSettings ( object o )
2013-12-23 02:51:41 +00:00
{
2016-12-04 17:19:34 +00:00
var settable = new SettingsAdapter ( Emulator ) ;
2013-12-23 02:51:41 +00:00
if ( Global . MovieSession . Movie . IsActive )
{
2014-09-06 15:17:22 +00:00
GlobalWin . OSD . AddMessage ( "Attempt to change sync-relevant settings while recording BLOCKED." ) ;
2013-12-23 02:51:41 +00:00
}
2015-09-14 00:17:07 +00:00
else if ( settable . HasSyncSettings & & settable . PutSyncSettings ( o ) )
2013-12-23 02:51:41 +00:00
{
2013-12-29 23:35:42 +00:00
FlagNeedsReboot ( ) ;
2013-12-23 02:51:41 +00:00
}
}
2016-01-27 16:07:26 +00:00
private void SaveConfig ( string path = "" )
2013-11-03 02:51:21 +00:00
{
if ( Global . Config . SaveWindowPosition )
{
2014-11-09 16:00:39 +00:00
if ( Global . Config . MainWndx ! = - 32000 ) // When minimized location is -32000, don't save this into the config file!
{
Global . Config . MainWndx = Location . X ;
}
if ( Global . Config . MainWndy ! = - 32000 )
{
Global . Config . MainWndy = Location . Y ;
}
2013-11-03 02:51:21 +00:00
}
else
{
Global . Config . MainWndx = - 1 ;
Global . Config . MainWndy = - 1 ;
}
2013-12-20 22:05:56 +00:00
if ( Global . Config . ShowLogWindow )
{
LogConsole . SaveConfigSettings ( ) ;
}
2016-01-27 16:07:26 +00:00
if ( string . IsNullOrEmpty ( path ) )
path = PathManager . DefaultIniPath ;
ConfigService . Save ( path , Global . Config ) ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
private static void ToggleFPS ( )
2013-11-03 02:51:21 +00:00
{
Global . Config . DisplayFPS ^ = true ;
}
2013-11-27 23:35:32 +00:00
private static void ToggleFrameCounter ( )
2013-11-03 02:51:21 +00:00
{
Global . Config . DisplayFrameCounter ^ = true ;
}
2013-11-27 23:35:32 +00:00
private static void ToggleLagCounter ( )
2013-11-03 02:51:21 +00:00
{
Global . Config . DisplayLagCounter ^ = true ;
}
2013-11-27 23:35:32 +00:00
private static void ToggleInputDisplay ( )
2013-11-03 02:51:21 +00:00
{
Global . Config . DisplayInput ^ = true ;
}
2015-01-25 03:33:45 +00:00
public static void ToggleSound ( )
{
Global . Config . SoundEnabled ^ = true ;
GlobalWin . Sound . StopSound ( ) ;
GlobalWin . Sound . StartSound ( ) ;
}
2013-11-27 23:35:32 +00:00
private static void VolumeUp ( )
2013-11-03 02:51:21 +00:00
{
Global . Config . SoundVolume + = 10 ;
if ( Global . Config . SoundVolume > 100 )
2013-11-27 23:35:32 +00:00
{
2013-11-03 02:51:21 +00:00
Global . Config . SoundVolume = 100 ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2016-03-29 08:40:37 +00:00
//GlobalWin.Sound.ApplyVolumeSettings();
2013-11-27 23:35:32 +00:00
GlobalWin . OSD . AddMessage ( "Volume " + Global . Config . SoundVolume ) ;
2013-11-03 02:51:21 +00:00
}
2013-11-27 23:35:32 +00:00
private static void VolumeDown ( )
2013-11-03 02:51:21 +00:00
{
Global . Config . SoundVolume - = 10 ;
if ( Global . Config . SoundVolume < 0 )
2013-11-27 23:35:32 +00:00
{
2013-11-03 02:51:21 +00:00
Global . Config . SoundVolume = 0 ;
2013-11-27 23:35:32 +00:00
}
2013-12-20 22:05:56 +00:00
2016-03-29 08:40:37 +00:00
//GlobalWin.Sound.ApplyVolumeSettings();
2013-11-27 23:35:32 +00:00
GlobalWin . OSD . AddMessage ( "Volume " + Global . Config . SoundVolume ) ;
2013-11-03 02:51:21 +00:00
}
2012-12-10 00:43:43 +00:00
2016-12-04 17:19:34 +00:00
private void SoftReset ( )
2012-12-10 00:43:43 +00:00
{
2013-12-20 22:05:56 +00:00
// is it enough to run this for one frame? maybe..
2016-12-04 17:19:34 +00:00
if ( Emulator . ControllerDefinition . BoolButtons . Contains ( "Reset" ) )
2013-10-11 16:32:36 +00:00
{
2013-11-03 02:51:21 +00:00
if ( ! Global . MovieSession . Movie . IsPlaying | | Global . MovieSession . Movie . IsFinished )
{
Global . ClickyVirtualPadController . Click ( "Reset" ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "Reset button pressed." ) ;
2013-11-03 02:51:21 +00:00
}
2013-10-11 16:32:36 +00:00
}
2013-11-03 02:51:21 +00:00
}
2013-10-11 16:32:36 +00:00
2016-12-04 17:19:34 +00:00
private void HardReset ( )
2013-11-03 02:51:21 +00:00
{
2013-12-20 22:05:56 +00:00
// is it enough to run this for one frame? maybe..
2016-12-04 17:19:34 +00:00
if ( Emulator . ControllerDefinition . BoolButtons . Contains ( "Power" ) )
2013-10-11 16:32:36 +00:00
{
2013-11-03 02:51:21 +00:00
if ( ! Global . MovieSession . Movie . IsPlaying | | Global . MovieSession . Movie . IsFinished )
2013-10-11 16:32:36 +00:00
{
2013-11-03 02:51:21 +00:00
Global . ClickyVirtualPadController . Click ( "Power" ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "Power button pressed." ) ;
2013-10-11 16:32:36 +00:00
}
}
2013-11-03 02:51:21 +00:00
}
private void UpdateStatusSlots ( )
{
2013-11-27 23:35:32 +00:00
_stateSlots . Update ( ) ;
2013-11-03 02:51:21 +00:00
2014-02-22 21:59:46 +00:00
Slot0StatusButton . ForeColor = _stateSlots . HasSlot ( 0 ) ? Global . Config . SaveSlot = = 0 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot1StatusButton . ForeColor = _stateSlots . HasSlot ( 1 ) ? Global . Config . SaveSlot = = 1 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot2StatusButton . ForeColor = _stateSlots . HasSlot ( 2 ) ? Global . Config . SaveSlot = = 2 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot3StatusButton . ForeColor = _stateSlots . HasSlot ( 3 ) ? Global . Config . SaveSlot = = 3 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot4StatusButton . ForeColor = _stateSlots . HasSlot ( 4 ) ? Global . Config . SaveSlot = = 4 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot5StatusButton . ForeColor = _stateSlots . HasSlot ( 5 ) ? Global . Config . SaveSlot = = 5 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot6StatusButton . ForeColor = _stateSlots . HasSlot ( 6 ) ? Global . Config . SaveSlot = = 6 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot7StatusButton . ForeColor = _stateSlots . HasSlot ( 7 ) ? Global . Config . SaveSlot = = 7 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot8StatusButton . ForeColor = _stateSlots . HasSlot ( 8 ) ? Global . Config . SaveSlot = = 8 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot9StatusButton . ForeColor = _stateSlots . HasSlot ( 9 ) ? Global . Config . SaveSlot = = 9 ? SystemColors . HighlightText : SystemColors . WindowText : SystemColors . GrayText ;
Slot0StatusButton . BackColor = Global . Config . SaveSlot = = 0 ? SystemColors . Highlight : SystemColors . Control ;
Slot1StatusButton . BackColor = Global . Config . SaveSlot = = 1 ? SystemColors . Highlight : SystemColors . Control ;
Slot2StatusButton . BackColor = Global . Config . SaveSlot = = 2 ? SystemColors . Highlight : SystemColors . Control ;
Slot3StatusButton . BackColor = Global . Config . SaveSlot = = 3 ? SystemColors . Highlight : SystemColors . Control ;
Slot4StatusButton . BackColor = Global . Config . SaveSlot = = 4 ? SystemColors . Highlight : SystemColors . Control ;
Slot5StatusButton . BackColor = Global . Config . SaveSlot = = 5 ? SystemColors . Highlight : SystemColors . Control ;
Slot6StatusButton . BackColor = Global . Config . SaveSlot = = 6 ? SystemColors . Highlight : SystemColors . Control ;
Slot7StatusButton . BackColor = Global . Config . SaveSlot = = 7 ? SystemColors . Highlight : SystemColors . Control ;
Slot8StatusButton . BackColor = Global . Config . SaveSlot = = 8 ? SystemColors . Highlight : SystemColors . Control ;
Slot9StatusButton . BackColor = Global . Config . SaveSlot = = 9 ? SystemColors . Highlight : SystemColors . Control ;
2014-11-30 19:52:32 +00:00
SaveSlotsStatusLabel . Visible =
Slot0StatusButton . Visible =
Slot1StatusButton . Visible =
Slot2StatusButton . Visible =
Slot3StatusButton . Visible =
Slot4StatusButton . Visible =
Slot5StatusButton . Visible =
Slot6StatusButton . Visible =
Slot7StatusButton . Visible =
Slot8StatusButton . Visible =
Slot9StatusButton . Visible =
2016-12-04 17:19:34 +00:00
Emulator . HasSavestates ( ) ;
2013-11-03 02:51:21 +00:00
}
2015-02-17 00:13:19 +00:00
public BitmapBuffer CaptureOSD ( )
2013-11-03 02:51:21 +00:00
{
2016-12-07 19:21:18 +00:00
var bb = GlobalWin . DisplayManager . RenderOffscreen ( _currentVideoProvider , true ) ;
2015-08-30 14:19:49 +00:00
bb . DiscardAlpha ( ) ;
2014-06-02 20:16:59 +00:00
return bb ;
2012-12-10 00:43:43 +00:00
}
2013-11-03 02:51:21 +00:00
private void IncreaseWindowSize ( )
2011-06-11 12:54:26 +00:00
{
2016-12-04 17:19:34 +00:00
switch ( Global . Config . TargetZoomFactors [ Emulator . SystemId ] )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
case 1 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 2 ;
2013-11-03 02:51:21 +00:00
break ;
case 2 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 3 ;
2013-11-03 02:51:21 +00:00
break ;
case 3 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 4 ;
2013-11-03 02:51:21 +00:00
break ;
case 4 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 5 ;
2013-11-03 02:51:21 +00:00
break ;
case 5 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 10 ;
2013-11-03 02:51:21 +00:00
break ;
case 10 :
return ;
2011-06-11 12:54:26 +00:00
}
2013-12-20 22:05:56 +00:00
2016-12-04 17:19:34 +00:00
GlobalWin . OSD . AddMessage ( "Screensize set to " + Global . Config . TargetZoomFactors [ Emulator . SystemId ] + "x" ) ;
2013-11-03 02:51:21 +00:00
FrameBufferResized ( ) ;
}
2015-12-05 09:09:39 +00:00
private void DecreaseWindowSize ( )
2013-11-03 02:51:21 +00:00
{
2016-12-04 17:19:34 +00:00
switch ( Global . Config . TargetZoomFactors [ Emulator . SystemId ] )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
case 1 :
return ;
case 2 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 1 ;
2013-11-03 02:51:21 +00:00
break ;
case 3 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 2 ;
2013-11-03 02:51:21 +00:00
break ;
case 4 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 3 ;
2013-11-03 02:51:21 +00:00
break ;
case 5 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 4 ;
2013-11-03 02:51:21 +00:00
break ;
case 10 :
2016-12-04 17:19:34 +00:00
Global . Config . TargetZoomFactors [ Emulator . SystemId ] = 5 ;
2013-11-03 02:51:21 +00:00
return ;
2011-06-11 12:54:26 +00:00
}
2013-12-20 22:05:56 +00:00
2016-12-04 17:19:34 +00:00
GlobalWin . OSD . AddMessage ( "Screensize set to " + Global . Config . TargetZoomFactors [ Emulator . SystemId ] + "x" ) ;
2013-11-03 02:51:21 +00:00
FrameBufferResized ( ) ;
}
2012-05-28 01:29:43 +00:00
2013-11-03 02:51:21 +00:00
private void IncreaseSpeed ( )
{
2014-06-21 20:18:14 +00:00
if ( ! Global . Config . ClockThrottle )
{
GlobalWin . OSD . AddMessage ( "Unable to change speed, please switch to clock throttle" ) ;
return ;
}
2013-12-29 23:35:42 +00:00
var oldp = Global . Config . SpeedPercent ;
2013-11-03 02:51:21 +00:00
int newp ;
2014-01-01 03:03:10 +00:00
2013-12-29 23:35:42 +00:00
if ( oldp < 3 )
{
newp = 3 ;
}
else if ( oldp < 6 )
{
newp = 6 ;
}
else if ( oldp < 12 )
{
newp = 12 ;
}
else if ( oldp < 25 )
{
newp = 25 ;
}
else if ( oldp < 50 )
{
newp = 50 ;
}
else if ( oldp < 75 )
{
newp = 75 ;
}
else if ( oldp < 100 )
{
newp = 100 ;
}
else if ( oldp < 150 )
{
newp = 150 ;
}
else if ( oldp < 200 )
{
newp = 200 ;
}
2014-09-05 20:37:56 +00:00
else if ( oldp < 300 )
{
newp = 300 ;
}
2013-12-29 23:35:42 +00:00
else if ( oldp < 400 )
{
newp = 400 ;
}
else if ( oldp < 800 )
{
newp = 800 ;
}
2014-01-10 16:49:17 +00:00
else if ( oldp < 1600 )
2013-12-29 23:35:42 +00:00
{
newp = 1600 ;
}
2014-09-05 20:37:56 +00:00
else if ( oldp < 3200 )
2014-01-10 16:49:17 +00:00
{
newp = 3200 ;
}
2014-09-05 20:37:56 +00:00
else
{
newp = 6400 ;
}
2013-12-29 23:35:42 +00:00
2013-11-03 02:51:21 +00:00
SetSpeedPercent ( newp ) ;
2012-04-21 22:46:48 +00:00
}
2013-11-03 02:51:21 +00:00
private void DecreaseSpeed ( )
2011-06-11 12:54:26 +00:00
{
2014-06-21 20:18:14 +00:00
if ( ! Global . Config . ClockThrottle )
{
GlobalWin . OSD . AddMessage ( "Unable to change speed, please switch to clock throttle" ) ;
return ;
}
2013-12-29 23:35:42 +00:00
var oldp = Global . Config . SpeedPercent ;
2013-11-03 02:51:21 +00:00
int newp ;
2014-01-01 03:03:10 +00:00
2014-09-05 20:37:56 +00:00
if ( oldp > 3200 )
{
newp = 3200 ;
}
else if ( oldp > 1600 )
2014-01-10 16:49:17 +00:00
{
newp = 1600 ;
}
else if ( oldp > 800 )
2013-12-29 23:35:42 +00:00
{
newp = 800 ;
}
else if ( oldp > 400 )
{
newp = 400 ;
}
2014-09-05 20:37:56 +00:00
else if ( oldp > 300 )
{
newp = 300 ;
}
2013-12-29 23:35:42 +00:00
else if ( oldp > 200 )
{
newp = 200 ;
}
else if ( oldp > 150 )
{
newp = 150 ;
}
else if ( oldp > 100 )
{
newp = 100 ;
}
else if ( oldp > 75 )
{
newp = 75 ;
}
else if ( oldp > 50 )
{
newp = 50 ;
}
else if ( oldp > 25 )
{
newp = 25 ;
}
else if ( oldp > 12 )
{
newp = 12 ;
}
else if ( oldp > 6 )
{
newp = 6 ;
}
else if ( oldp > 3 )
{
newp = 3 ;
}
else
{
newp = 1 ;
}
2013-11-03 02:51:21 +00:00
SetSpeedPercent ( newp ) ;
2011-06-11 12:54:26 +00:00
}
2013-11-27 23:35:32 +00:00
private static void SaveMovie ( )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
if ( Global . MovieSession . Movie . IsActive )
{
2013-11-23 18:18:58 +00:00
Global . MovieSession . Movie . Save ( ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( Global . MovieSession . Movie . Filename + " saved." ) ;
2013-11-03 02:51:21 +00:00
}
2011-06-11 12:54:26 +00:00
}
2014-08-23 01:18:59 +00:00
private void HandleToggleLightAndLink ( )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
if ( MainStatusBar . Visible )
{
2016-12-04 17:19:34 +00:00
var hasDriveLight = Emulator . HasDriveLight ( ) & & Emulator . AsDriveLight ( ) . DriveLightEnabled ;
2014-12-12 01:49:54 +00:00
if ( hasDriveLight )
2013-11-03 02:51:21 +00:00
{
if ( ! LedLightStatusLabel . Visible )
{
LedLightStatusLabel . Visible = true ;
}
2013-12-20 22:05:56 +00:00
2016-12-04 17:19:34 +00:00
LedLightStatusLabel . Image = Emulator . AsDriveLight ( ) . DriveLightOn
2014-02-17 09:20:08 +00:00
? StatusBarDiskLightOnImage
: StatusBarDiskLightOffImage ;
2013-11-03 02:51:21 +00:00
}
else
{
if ( LedLightStatusLabel . Visible )
{
LedLightStatusLabel . Visible = false ;
}
}
2014-08-23 01:18:59 +00:00
2016-12-04 17:19:34 +00:00
if ( Emulator . UsesLinkCable ( ) )
2014-08-23 01:18:59 +00:00
{
if ( ! LinkConnectStatusBarButton . Visible )
{
LinkConnectStatusBarButton . Visible = true ;
}
2016-12-04 17:19:34 +00:00
LinkConnectStatusBarButton . Image = Emulator . AsLinkable ( ) . LinkConnected
2014-08-23 01:18:59 +00:00
? LinkCableOn
: LinkCableOff ;
}
else
{
if ( LinkConnectStatusBarButton . Visible )
{
LinkConnectStatusBarButton . Visible = false ;
}
}
2013-11-03 02:51:21 +00:00
}
2011-06-11 12:54:26 +00:00
}
2013-11-03 02:51:21 +00:00
private void UpdateKeyPriorityIcon ( )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
switch ( Global . Config . Input_Hotkey_OverrideOptions )
{
default :
case 0 :
KeyPriorityStatusLabel . Image = Properties . Resources . Both ;
KeyPriorityStatusLabel . ToolTipText = "Key priority: Allow both hotkeys and controller buttons" ;
break ;
case 1 :
KeyPriorityStatusLabel . Image = Properties . Resources . GameController ;
KeyPriorityStatusLabel . ToolTipText = "Key priority: Controller buttons will override hotkeys" ;
break ;
case 2 :
KeyPriorityStatusLabel . Image = Properties . Resources . HotKeys ;
KeyPriorityStatusLabel . ToolTipText = "Key priority: Hotkeys will override controller buttons" ;
break ;
}
2011-06-11 12:54:26 +00:00
}
2013-11-27 23:35:32 +00:00
private static void ToggleModePokeMode ( )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
Global . Config . MoviePlaybackPokeMode ^ = true ;
2013-11-27 23:35:32 +00:00
GlobalWin . OSD . AddMessage ( Global . Config . MoviePlaybackPokeMode ? "Movie Poke mode enabled" : "Movie Poke mode disabled" ) ;
2011-06-11 12:54:26 +00:00
}
2013-11-27 23:35:32 +00:00
private static void ToggleBackgroundInput ( )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
Global . Config . AcceptBackgroundInput ^ = true ;
2013-11-27 23:35:32 +00:00
GlobalWin . OSD . AddMessage ( Global . Config . AcceptBackgroundInput
2014-01-01 03:03:10 +00:00
? "Background Input enabled"
: "Background Input disabled" ) ;
2011-06-11 12:54:26 +00:00
}
2013-11-27 23:35:32 +00:00
private static void LimitFrameRateMessage ( )
2011-06-11 12:54:26 +00:00
{
2013-11-27 23:35:32 +00:00
GlobalWin . OSD . AddMessage ( Global . Config . ClockThrottle ? "Framerate limiting on" : "Framerate limiting off" ) ;
2011-06-11 23:54:35 +00:00
}
2013-11-27 23:35:32 +00:00
private static void VsyncMessage ( )
2011-06-11 12:54:26 +00:00
{
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage (
2016-03-26 16:47:22 +00:00
"Display Vsync set to " + ( Global . Config . VSync ? "on" : "off" )
2013-11-03 02:51:21 +00:00
) ;
2011-06-11 12:54:26 +00:00
}
2013-11-27 23:35:32 +00:00
private static bool StateErrorAskUser ( string title , string message )
2011-06-11 12:54:26 +00:00
{
2013-12-20 22:05:56 +00:00
var result = MessageBox . Show (
message ,
2013-11-03 02:51:21 +00:00
title ,
MessageBoxButtons . YesNo ,
MessageBoxIcon . Question
) ;
return result = = DialogResult . Yes ;
2011-06-18 18:27:51 +00:00
}
2011-06-26 21:11:12 +00:00
2013-12-20 22:49:35 +00:00
private void FdsInsertDiskMenuAdd ( string name , string button , string msg )
{
FDSControlsMenuItem . DropDownItems . Add ( name , null , delegate
{
2016-12-04 17:19:34 +00:00
if ( Emulator . ControllerDefinition . BoolButtons . Contains ( button ) )
2013-12-20 22:49:35 +00:00
{
if ( ! Global . MovieSession . Movie . IsPlaying | | Global . MovieSession . Movie . IsFinished )
{
Global . ClickyVirtualPadController . Click ( button ) ;
GlobalWin . OSD . AddMessage ( msg ) ;
}
}
} ) ;
}
2016-09-22 01:23:57 +00:00
private const int WM_DEVICECHANGE = 0x0219 ;
2013-12-20 22:05:56 +00:00
// Alt key hacks
2013-11-03 02:51:21 +00:00
protected override void WndProc ( ref Message m )
2011-06-30 02:22:12 +00:00
{
2016-09-22 01:23:57 +00:00
switch ( m . Msg )
{
case WM_DEVICECHANGE :
GamePad . Initialize ( ) ;
GamePad360 . Initialize ( ) ;
break ;
}
2013-12-20 22:05:56 +00:00
// this is necessary to trap plain alt keypresses so that only our hotkey system gets them
if ( m . Msg = = 0x0112 ) // WM_SYSCOMMAND
{
if ( m . WParam . ToInt32 ( ) = = 0xF100 ) // SC_KEYMENU
{
2013-11-03 02:51:21 +00:00
return ;
2013-12-20 22:05:56 +00:00
}
}
2013-11-03 02:51:21 +00:00
base . WndProc ( ref m ) ;
2011-06-30 02:22:12 +00:00
}
2011-07-01 01:28:25 +00:00
2013-11-03 02:51:21 +00:00
protected override bool ProcessDialogChar ( char charCode )
2012-09-16 16:52:30 +00:00
{
2013-12-20 22:05:56 +00:00
// this is necessary to trap alt+char combinations so that only our hotkey system gets them
2013-11-27 23:35:32 +00:00
return ( ModifierKeys & Keys . Alt ) ! = 0 | | base . ProcessDialogChar ( charCode ) ;
2012-09-16 16:52:30 +00:00
}
2014-04-25 01:19:57 +00:00
private void UpdateCoreStatusBarButton ( )
{
2016-12-04 17:19:34 +00:00
if ( Emulator . IsNull ( ) )
2014-04-25 01:19:57 +00:00
{
CoreNameStatusBarButton . Visible = false ;
return ;
}
CoreNameStatusBarButton . Visible = true ;
2016-12-04 17:19:34 +00:00
var attributes = Emulator . Attributes ( ) ;
2014-04-25 01:19:57 +00:00
2016-12-04 17:19:34 +00:00
CoreNameStatusBarButton . Text = Emulator . DisplayName ( ) ;
CoreNameStatusBarButton . Image = Emulator . Icon ( ) ;
2014-04-25 21:55:56 +00:00
CoreNameStatusBarButton . ToolTipText = attributes . Ported ? "(ported) " : string . Empty ;
2014-04-25 01:19:57 +00:00
}
2013-11-03 02:51:21 +00:00
#endregion
#region Frame Loop
private void StepRunLoop_Throttle ( )
2011-07-01 01:28:25 +00:00
{
2013-11-03 02:51:21 +00:00
SyncThrottle ( ) ;
2013-11-27 23:35:32 +00:00
_throttle . signal_frameAdvance = _runloopFrameadvance ;
_throttle . signal_continuousframeAdvancing = _runloopFrameProgress ;
2011-07-01 01:28:25 +00:00
2013-11-27 23:35:32 +00:00
_throttle . Step ( true , - 1 ) ;
2013-11-03 02:51:21 +00:00
}
2012-10-07 19:52:09 +00:00
2014-10-05 14:11:30 +00:00
public void FrameAdvance ( )
{
2014-10-11 16:58:57 +00:00
PressFrameAdvance = true ;
2014-10-23 21:21:43 +00:00
StepRunLoop_Core ( true ) ;
2014-10-05 14:11:30 +00:00
}
2014-11-30 20:29:30 +00:00
public bool IsLagFrame
{
get
{
2016-12-04 17:19:34 +00:00
if ( Emulator . CanPollInput ( ) )
2014-11-30 20:29:30 +00:00
{
2016-12-04 17:19:34 +00:00
return Emulator . AsInputPollable ( ) . IsLagFrame ;
2014-11-30 20:29:30 +00:00
}
return false ;
}
}
2014-10-11 16:58:57 +00:00
private void StepRunLoop_Core ( bool force = false )
2013-11-03 02:51:21 +00:00
{
2013-12-29 23:35:42 +00:00
var runFrame = false ;
2013-11-27 23:35:32 +00:00
_runloopFrameadvance = false ;
2015-01-31 22:16:02 +00:00
var currentTimestamp = Stopwatch . GetTimestamp ( ) ;
2013-12-29 23:35:42 +00:00
var suppressCaptureRewind = false ;
2012-10-07 19:52:09 +00:00
2015-01-31 22:16:02 +00:00
double frameAdvanceTimestampDeltaMs = ( double ) ( currentTimestamp - _frameAdvanceTimestamp ) / Stopwatch . Frequency * 1000.0 ;
bool frameProgressTimeElapsed = frameAdvanceTimestampDeltaMs > = Global . Config . FrameProgressDelayMs ;
2012-10-07 19:52:09 +00:00
2016-12-04 17:19:34 +00:00
if ( Global . Config . SkipLagFrame & & IsLagFrame & & frameProgressTimeElapsed & & Emulator . Frame > 0 )
2012-10-07 19:52:09 +00:00
{
2013-11-03 02:51:21 +00:00
runFrame = true ;
2012-10-07 19:52:09 +00:00
}
2016-08-28 15:42:59 +00:00
if ( Global . ClientControls [ "Frame Advance" ] | | PressFrameAdvance | | HoldFrameAdvance )
2012-10-07 19:52:09 +00:00
{
2016-09-29 05:02:38 +00:00
_runloopFrameadvance = true ;
2013-12-29 23:35:42 +00:00
// handle the initial trigger of a frame advance
2015-01-31 22:16:02 +00:00
if ( _frameAdvanceTimestamp = = 0 )
2013-11-03 02:51:21 +00:00
{
PauseEmulator ( ) ;
runFrame = true ;
2015-01-31 22:16:02 +00:00
_frameAdvanceTimestamp = currentTimestamp ;
2013-11-03 02:51:21 +00:00
}
else
{
2013-12-29 23:35:42 +00:00
// handle the timed transition from countdown to FrameProgress
2013-11-03 02:51:21 +00:00
if ( frameProgressTimeElapsed )
{
runFrame = true ;
2013-11-27 23:35:32 +00:00
_runloopFrameProgress = true ;
2013-11-03 02:51:21 +00:00
UnpauseEmulator ( ) ;
}
}
2012-10-07 19:52:09 +00:00
}
else
{
2013-12-29 23:35:42 +00:00
// handle release of frame advance: do we need to deactivate FrameProgress?
2013-11-27 23:35:32 +00:00
if ( _runloopFrameProgress )
2013-11-03 02:51:21 +00:00
{
2013-11-27 23:35:32 +00:00
_runloopFrameProgress = false ;
2013-11-03 02:51:21 +00:00
PauseEmulator ( ) ;
}
2013-12-29 23:35:42 +00:00
2015-01-31 22:16:02 +00:00
_frameAdvanceTimestamp = 0 ;
2012-10-07 19:52:09 +00:00
}
2013-11-03 02:51:21 +00:00
if ( ! EmulatorPaused )
2012-10-07 19:52:09 +00:00
{
2013-11-03 02:51:21 +00:00
runFrame = true ;
2012-10-07 19:52:09 +00:00
}
2015-01-31 22:16:02 +00:00
bool isRewinding = suppressCaptureRewind = Rewind ( ref runFrame , currentTimestamp ) ;
2016-09-29 04:24:09 +00:00
2016-09-29 04:48:35 +00:00
float atten = 0 ;
2013-12-27 00:47:52 +00:00
2014-10-11 16:58:57 +00:00
if ( runFrame | | force )
2012-10-07 19:52:09 +00:00
{
2014-07-27 17:49:25 +00:00
var isFastForwarding = Global . ClientControls [ "Fast Forward" ] | | IsTurboing ;
2013-12-29 23:35:42 +00:00
var updateFpsString = _runloopLastFf ! = isFastForwarding ;
_runloopLastFf = isFastForwarding ;
2013-11-03 02:51:21 +00:00
2013-12-29 23:35:42 +00:00
// client input-related duties
2013-11-20 02:14:29 +00:00
GlobalWin . OSD . ClearGUIText ( ) ;
2014-01-01 03:19:08 +00:00
Global . CheatList . Pulse ( ) ;
2014-05-03 09:02:17 +00:00
//zero 03-may-2014 - moved this before call to UpdateToolsBefore(), since it seems to clear the state which a lua event.framestart is going to want to alter
Global . ClickyVirtualPadController . FrameTick ( ) ;
Global . LuaAndAdaptor . FrameTick ( ) ;
2014-05-03 11:59:11 +00:00
if ( GlobalWin . Tools . Has < LuaConsole > ( ) )
{
GlobalWin . Tools . LuaConsole . LuaImp . CallFrameBeforeEvent ( ) ;
}
2015-07-09 23:35:00 +00:00
if ( IsTurboing )
2013-11-03 02:51:21 +00:00
{
2015-07-09 23:35:00 +00:00
GlobalWin . Tools . FastUpdateBefore ( ) ;
2013-11-03 02:51:21 +00:00
}
2014-07-25 01:55:21 +00:00
else
{
2015-07-09 23:35:00 +00:00
GlobalWin . Tools . UpdateToolsBefore ( ) ;
2014-07-25 01:55:21 +00:00
}
2013-11-03 02:51:21 +00:00
2016-09-29 04:04:53 +00:00
_runloopLastFps + = _runloopFpsSmoothing ;
2013-11-03 02:51:21 +00:00
2016-09-29 07:04:39 +00:00
UpdateFpsDisplay ( currentTimestamp , updateFpsString , isRewinding , isFastForwarding ) ;
2013-11-03 02:51:21 +00:00
2014-09-27 12:19:50 +00:00
CaptureRewind ( suppressCaptureRewind ) ;
2013-11-03 02:51:21 +00:00
2016-09-29 05:37:26 +00:00
// Set volume, if enabled
2016-09-29 04:48:35 +00:00
if ( Global . Config . SoundEnabledNormal )
2013-11-03 02:51:21 +00:00
{
2016-09-29 05:37:26 +00:00
atten = Global . Config . SoundVolume / 100.0f ;
2016-03-29 08:40:37 +00:00
2016-09-29 05:37:26 +00:00
if ( isFastForwarding | | IsTurboing | | isRewinding )
2014-07-11 17:14:45 +00:00
{
2016-09-29 05:37:26 +00:00
if ( Global . Config . SoundEnabledRWFF )
2016-09-29 08:10:23 +00:00
atten * = Global . Config . SoundVolumeRWFF / 100.0f ;
2014-07-11 17:14:45 +00:00
else
2016-09-29 05:37:26 +00:00
atten = 0 ;
2013-11-03 02:51:21 +00:00
}
2013-12-29 23:35:42 +00:00
2016-09-29 05:37:26 +00:00
// Mute if using Frame Advance/Frame Progress
if ( _runloopFrameadvance & & Global . Config . MuteFrameAdvance )
{
2016-03-29 08:40:37 +00:00
atten = 0 ;
2016-09-29 05:37:26 +00:00
}
2013-12-29 23:35:42 +00:00
}
2016-09-29 05:37:26 +00:00
2013-11-03 16:53:05 +00:00
Global . MovieSession . HandleMovieOnFrameLoop ( ) ;
2013-11-03 02:51:21 +00:00
2015-08-18 04:14:40 +00:00
//why not skip audio if the user doesnt want sound
2016-09-29 06:14:18 +00:00
bool renderSound = Global . Config . SoundEnabled | | ! IsTurboing ;
renderSound | = ( _currAviWriter ! = null & & _currAviWriter . UsesAudio ) ;
2015-08-18 04:14:40 +00:00
2016-09-29 06:14:18 +00:00
bool render = ! _throttle . skipnextframe | | ( _currAviWriter ! = null & & _currAviWriter . UsesVideo ) ;
2016-12-04 17:19:34 +00:00
Emulator . FrameAdvance ( render , renderSound ) ;
2015-08-18 04:14:40 +00:00
2014-06-08 23:30:34 +00:00
2015-03-16 20:42:14 +00:00
Global . MovieSession . HandleMovieAfterFrameLoop ( ) ;
2013-11-03 02:51:21 +00:00
Global . CheatList . Pulse ( ) ;
if ( ! PauseAVI )
{
2014-01-10 16:54:53 +00:00
AvFrameAdvance ( ) ;
2013-11-03 02:51:21 +00:00
}
2014-11-30 20:29:30 +00:00
if ( IsLagFrame & & Global . Config . AutofireLagFrames )
2013-11-03 02:51:21 +00:00
{
Global . AutoFireController . IncrementStarts ( ) ;
}
2015-03-08 04:42:04 +00:00
Global . AutofireStickyXORAdapter . IncrementLoops ( IsLagFrame ) ;
2012-10-07 19:52:09 +00:00
2013-11-03 02:51:21 +00:00
PressFrameAdvance = false ;
2014-05-03 11:59:11 +00:00
if ( GlobalWin . Tools . Has < LuaConsole > ( ) )
{
GlobalWin . Tools . LuaConsole . LuaImp . CallFrameAfterEvent ( ) ;
}
2015-07-09 23:25:59 +00:00
if ( IsTurboing )
2013-11-03 02:51:21 +00:00
{
2015-07-09 23:25:59 +00:00
GlobalWin . Tools . FastUpdateAfter ( ) ;
2013-11-03 02:51:21 +00:00
}
2014-07-25 01:55:21 +00:00
else
{
2015-07-09 23:25:59 +00:00
UpdateToolsAfter ( ) ;
2014-07-25 01:55:21 +00:00
}
2014-07-26 13:06:19 +00:00
2016-08-27 22:08:43 +00:00
if ( GlobalWin . Tools . IsLoaded < TAStudio > ( ) & &
2016-12-04 17:19:34 +00:00
GlobalWin . Tools . TAStudio . LastPositionFrame = = Emulator . Frame )
2016-08-27 22:08:43 +00:00
{
2016-09-09 16:15:00 +00:00
if ( PauseOnFrame . HasValue & &
PauseOnFrame . Value < = GlobalWin . Tools . TAStudio . LastPositionFrame )
2016-09-08 20:29:17 +00:00
{
2016-12-04 17:19:34 +00:00
TasMovieRecord record = ( Global . MovieSession . Movie as TasMovie ) [ Emulator . Frame ] ;
2016-09-08 20:29:17 +00:00
if ( ! record . Lagged . HasValue & & IsSeeking )
// haven't yet greenzoned the frame, hence it's after editing
// then we want to pause here. taseditor fasion
PauseEmulator ( ) ;
}
2016-08-27 22:08:43 +00:00
}
2016-12-04 17:19:34 +00:00
if ( IsSeeking & & Emulator . Frame = = PauseOnFrame . Value )
2014-07-26 13:06:19 +00:00
{
2015-12-12 20:59:55 +00:00
PauseEmulator ( ) ;
PauseOnFrame = null ;
if ( GlobalWin . Tools . IsLoaded < TAStudio > ( ) )
2015-12-09 22:38:06 +00:00
{
2015-12-12 20:59:55 +00:00
GlobalWin . Tools . TAStudio . StopSeeking ( ) ;
2015-12-09 22:38:06 +00:00
}
2014-07-26 13:06:19 +00:00
}
2012-10-07 19:52:09 +00:00
}
2013-11-03 16:47:21 +00:00
if ( Global . ClientControls [ "Rewind" ] | | PressRewind )
2012-10-07 19:52:09 +00:00
{
2013-11-03 02:51:21 +00:00
UpdateToolsAfter ( ) ;
2016-08-28 15:42:59 +00:00
//PressRewind = false;
2012-10-07 19:52:09 +00:00
}
2013-12-29 23:35:42 +00:00
2016-03-29 08:40:37 +00:00
GlobalWin . Sound . UpdateSound ( atten ) ;
2011-07-01 01:28:25 +00:00
}
2016-09-29 07:04:39 +00:00
private void UpdateFpsDisplay ( long currentTimestamp , bool updateFpsString , bool isRewinding , bool isFastForwarding )
{
var timeDiff = ( currentTimestamp - _runloopSecond ) ;
if ( timeDiff * _runloopUpdatesPerSecond > = Stopwatch . Frequency )
2012-10-07 19:52:09 +00:00
{
2016-09-29 07:04:39 +00:00
_runloopLastFps = Stopwatch . Frequency * ( _runloopLastFps / ( Stopwatch . Frequency + timeDiff * _runloopFpsSmoothing ) ) ;
_runloopSecond = currentTimestamp ;
_runloopDisplayFps = _runloopLastFps ;
updateFpsString = true ;
2012-10-07 19:52:09 +00:00
}
2016-09-29 07:04:39 +00:00
if ( updateFpsString )
{
var fps_string = string . Format ( "{0:0} fps" , _runloopDisplayFps ) ;
if ( isRewinding )
{
if ( IsTurboing | | isFastForwarding )
{
fps_string + = " <<<<" ;
}
else
{
fps_string + = " <<" ;
}
}
else if ( IsTurboing )
{
fps_string + = " >>>>" ;
}
else if ( isFastForwarding )
{
fps_string + = " >>" ;
}
GlobalWin . OSD . FPS = fps_string ;
//need to refresh window caption in this case
if ( Global . Config . DispSpeedupFeatures = = 0 )
SetWindowText ( ) ;
}
2011-07-01 01:28:25 +00:00
}
2013-11-03 02:51:21 +00:00
#endregion
2012-11-26 21:08:08 +00:00
#region AVI Stuff
2012-07-23 00:33:30 +00:00
/// <summary>
/// start avi recording, unattended
/// </summary>
/// <param name="videowritername">match the short name of an ivideowriter</param>
/// <param name="filename">filename to save to</param>
2013-12-29 23:35:42 +00:00
private void RecordAv ( string videowritername , string filename )
2012-07-23 00:33:30 +00:00
{
2013-12-29 23:35:42 +00:00
_RecordAv ( videowritername , filename , true ) ;
2012-07-23 00:33:30 +00:00
}
/// <summary>
/// start avi recording, asking user for filename and options
/// </summary>
2013-12-29 23:35:42 +00:00
private void RecordAv ( )
2012-07-23 00:33:30 +00:00
{
2013-12-29 23:35:42 +00:00
_RecordAv ( null , null , false ) ;
2012-07-23 00:33:30 +00:00
}
/// <summary>
2013-12-29 23:35:42 +00:00
/// start AV recording
2012-07-23 00:33:30 +00:00
/// </summary>
2013-12-29 23:35:42 +00:00
private void _RecordAv ( string videowritername , string filename , bool unattended )
2011-07-09 21:13:18 +00:00
{
2013-12-29 23:35:42 +00:00
if ( _currAviWriter ! = null )
{
return ;
}
2012-06-13 19:50:50 +00:00
// select IVideoWriter to use
2012-07-23 00:33:30 +00:00
IVideoWriter aw = null ;
2015-12-16 18:13:15 +00:00
if ( string . IsNullOrEmpty ( videowritername ) & & ! string . IsNullOrEmpty ( Global . Config . VideoWriter ) )
videowritername = Global . Config . VideoWriter ;
if ( unattended & & ! string . IsNullOrEmpty ( videowritername ) )
2012-07-23 00:33:30 +00:00
{
2014-10-10 18:09:00 +00:00
aw = VideoWriterInventory . GetVideoWriter ( videowritername ) ;
2012-07-23 00:33:30 +00:00
}
else
{
2014-10-11 03:33:09 +00:00
aw = VideoWriterChooserForm . DoVideoWriterChoserDlg ( VideoWriterInventory . GetAllWriters ( ) , this ,
out _avwriterResizew , out _avwriterResizeh , out _avwriterpad , out _dumpaudiosync ) ;
2011-07-11 23:26:20 +00:00
}
2012-07-23 00:33:30 +00:00
2012-06-13 19:50:50 +00:00
if ( aw = = null )
2011-07-11 23:26:20 +00:00
{
2013-12-29 23:35:42 +00:00
GlobalWin . OSD . AddMessage (
unattended ? string . Format ( "Couldn't start video writer \"{0}\"" , videowritername ) : "A/V capture canceled." ) ;
2011-07-11 23:26:20 +00:00
return ;
2012-06-13 19:50:50 +00:00
}
2011-08-09 00:51:46 +00:00
2011-07-11 23:26:20 +00:00
try
{
2015-12-19 11:12:22 +00:00
bool usingAvi = aw is AviWriter ; //SO GROSS!
2014-10-11 03:33:09 +00:00
if ( _dumpaudiosync )
{
aw = new VideoStretcher ( aw ) ;
}
else
{
aw = new AudioStretcher ( aw ) ;
}
2016-12-04 17:19:34 +00:00
aw . SetMovieParameters ( Emulator . CoreComm . VsyncNum , Emulator . CoreComm . VsyncDen ) ;
2013-11-27 23:35:32 +00:00
if ( _avwriterResizew > 0 & & _avwriterResizeh > 0 )
2013-12-29 23:35:42 +00:00
{
2013-11-27 23:35:32 +00:00
aw . SetVideoParameters ( _avwriterResizew , _avwriterResizeh ) ;
2013-12-29 23:35:42 +00:00
}
2012-11-26 02:25:23 +00:00
else
2013-12-29 23:35:42 +00:00
{
2016-12-07 19:21:18 +00:00
aw . SetVideoParameters ( _currentVideoProvider . BufferWidth , _currentVideoProvider . BufferHeight ) ;
2013-12-29 23:35:42 +00:00
}
2011-07-11 23:26:20 +00:00
aw . SetAudioParameters ( 44100 , 2 , 16 ) ;
2012-06-13 19:50:50 +00:00
// select codec token
// do this before save dialog because ffmpeg won't know what extension it wants until it's been configured
2015-12-16 18:13:15 +00:00
if ( unattended & & ! string . IsNullOrEmpty ( filename ) )
2012-05-28 01:29:43 +00:00
{
2012-07-23 00:33:30 +00:00
aw . SetDefaultVideoCodecToken ( ) ;
}
else
{
2015-12-19 11:12:22 +00:00
//THIS IS REALLY SLOPPY!
//PLEASE REDO ME TO NOT CARE WHICH AVWRITER IS USED!
if ( usingAvi & & ! string . IsNullOrEmpty ( Global . Config . AVICodecToken ) )
aw . SetDefaultVideoCodecToken ( ) ;
2015-02-22 03:26:00 +00:00
var token = aw . AcquireVideoCodecToken ( this ) ;
2012-07-23 00:33:30 +00:00
if ( token = = null )
{
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "A/V capture canceled." ) ;
2012-07-23 00:33:30 +00:00
aw . Dispose ( ) ;
return ;
}
2013-12-29 23:35:42 +00:00
2012-07-23 00:33:30 +00:00
aw . SetVideoCodecToken ( token ) ;
2012-05-28 01:29:43 +00:00
}
2012-06-13 19:50:50 +00:00
// select file to save to
2015-12-16 18:13:15 +00:00
if ( unattended & & ! string . IsNullOrEmpty ( filename ) )
2012-06-13 19:50:50 +00:00
{
2012-07-23 00:33:30 +00:00
aw . OpenFile ( filename ) ;
2012-06-13 19:50:50 +00:00
}
else
{
2014-06-18 02:28:07 +00:00
string ext = aw . DesiredExtension ( ) ;
string pathForOpenFile ;
//handle directories first
if ( ext = = "<directory>" )
2012-07-23 00:33:30 +00:00
{
2014-06-18 02:28:07 +00:00
var fbd = new FolderBrowserEx ( ) ;
2014-06-29 02:28:48 +00:00
if ( fbd . ShowDialog ( ) = = DialogResult . Cancel )
2014-06-18 02:28:07 +00:00
{
aw . Dispose ( ) ;
return ;
}
pathForOpenFile = fbd . SelectedPath ;
2012-07-23 00:33:30 +00:00
}
else
{
2014-06-18 02:28:07 +00:00
var sfd = new SaveFileDialog ( ) ;
2014-11-30 18:52:46 +00:00
if ( Global . Game ! = null )
2014-06-18 02:28:07 +00:00
{
sfd . FileName = PathManager . FilesystemSafeName ( Global . Game ) + "." + ext ; //dont use Path.ChangeExtension, it might wreck game names with dots in them
sfd . InitialDirectory = PathManager . MakeAbsolutePath ( Global . Config . PathEntries . AvPathFragment , null ) ;
}
else
{
sfd . FileName = "NULL" ;
sfd . InitialDirectory = PathManager . MakeAbsolutePath ( Global . Config . PathEntries . AvPathFragment , null ) ;
}
2013-12-29 23:35:42 +00:00
2014-11-30 18:52:46 +00:00
sfd . Filter = string . Format ( "{0} (*.{0})|*.{0}|All Files|*.*" , ext ) ;
2012-06-13 19:50:50 +00:00
2014-06-18 02:28:07 +00:00
var result = sfd . ShowHawkDialog ( ) ;
if ( result = = DialogResult . Cancel )
{
aw . Dispose ( ) ;
return ;
}
pathForOpenFile = sfd . FileName ;
2012-07-23 00:33:30 +00:00
}
2013-12-29 23:35:42 +00:00
2014-06-18 02:28:07 +00:00
aw . OpenFile ( pathForOpenFile ) ;
2012-06-13 19:50:50 +00:00
}
2013-12-29 23:35:42 +00:00
// commit the avi writing last, in case there were any errors earlier
2013-11-27 23:35:32 +00:00
_currAviWriter = aw ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "A/V capture started" ) ;
2013-04-16 00:19:31 +00:00
AVIStatusLabel . Image = Properties . Resources . AVI ;
2012-06-13 19:50:50 +00:00
AVIStatusLabel . ToolTipText = "A/V capture in progress" ;
2012-09-29 22:37:34 +00:00
AVIStatusLabel . Visible = true ;
2011-07-11 23:26:20 +00:00
}
catch
{
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "A/V capture failed!" ) ;
2011-07-11 23:26:20 +00:00
aw . Dispose ( ) ;
throw ;
}
2012-06-13 19:50:50 +00:00
2014-10-11 03:33:09 +00:00
if ( _dumpaudiosync )
{
2016-12-11 17:14:42 +00:00
_currentSoundProvider . SetSyncMode ( SyncSoundMode . Sync ) ;
2014-10-11 03:33:09 +00:00
}
else
{
2016-12-11 20:01:42 +00:00
if ( _currentSoundProvider . CanProvideAsync )
{
_currentSoundProvider . SetSyncMode ( SyncSoundMode . Async ) ;
_aviSoundInputAsync = _currentSoundProvider ;
}
else
{
_currentSoundProvider . SetSyncMode ( SyncSoundMode . Sync ) ;
_aviSoundInputAsync = new MetaspuAsync ( _currentSoundProvider , ESynchMethod . ESynchMethod_V ) ;
}
2014-10-11 03:33:09 +00:00
}
2016-12-12 03:37:28 +00:00
_dumpProxy = new SimpleSyncSoundProvider ( ) ;
sound api changes. added a new ISyncSoundProvider, which works similarly to ISoundProvider except the source (not the sink) determines the number of samples to process. Added facilities to metaspu, dcfilter, speexresampler to work with ISyncSoundProvider. Add ISyncSoundProvider to IEmulator. All IEmulators must provide sync sound, but they need not provide async sound. When async is needed and an IEmulator doesn't provide it, the frontend will wrap it in a vecna metaspu. SNES, GB changed to provide sync sound only. All other emulator cores mostly unchanged; they just provide stub fakesync alongside async, for now. For the moment, the only use of the sync sound is for realtime audio throttling, where it works and sounds quite nice. In the future, sync sound will be supported for AV dumping as well.
2012-10-11 00:44:59 +00:00
RewireSound ( ) ;
2011-07-09 21:13:18 +00:00
}
2011-07-10 00:04:33 +00:00
2013-12-29 23:35:42 +00:00
private void AbortAv ( )
2012-10-18 20:57:53 +00:00
{
2013-11-27 23:35:32 +00:00
if ( _currAviWriter = = null )
2012-10-18 20:57:53 +00:00
{
2013-11-27 23:35:32 +00:00
_dumpProxy = null ;
2012-10-18 20:57:53 +00:00
RewireSound ( ) ;
return ;
}
2013-12-29 23:35:42 +00:00
2013-11-27 23:35:32 +00:00
_currAviWriter . Dispose ( ) ;
_currAviWriter = null ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "A/V capture aborted" ) ;
2013-04-16 00:19:31 +00:00
AVIStatusLabel . Image = Properties . Resources . Blank ;
2013-12-20 22:05:56 +00:00
AVIStatusLabel . ToolTipText = string . Empty ;
2012-10-18 20:57:53 +00:00
AVIStatusLabel . Visible = false ;
2016-12-11 17:14:42 +00:00
_aviSoundInputAsync = null ;
2013-11-27 23:35:32 +00:00
_dumpProxy = null ; // return to normal sound output
2012-10-18 20:57:53 +00:00
RewireSound ( ) ;
}
2013-12-29 23:35:42 +00:00
private void StopAv ( )
2011-07-10 00:04:33 +00:00
{
2013-11-27 23:35:32 +00:00
if ( _currAviWriter = = null )
2012-05-28 01:29:43 +00:00
{
2013-11-27 23:35:32 +00:00
_dumpProxy = null ;
sound api changes. added a new ISyncSoundProvider, which works similarly to ISoundProvider except the source (not the sink) determines the number of samples to process. Added facilities to metaspu, dcfilter, speexresampler to work with ISyncSoundProvider. Add ISyncSoundProvider to IEmulator. All IEmulators must provide sync sound, but they need not provide async sound. When async is needed and an IEmulator doesn't provide it, the frontend will wrap it in a vecna metaspu. SNES, GB changed to provide sync sound only. All other emulator cores mostly unchanged; they just provide stub fakesync alongside async, for now. For the moment, the only use of the sync sound is for realtime audio throttling, where it works and sounds quite nice. In the future, sync sound will be supported for AV dumping as well.
2012-10-11 00:44:59 +00:00
RewireSound ( ) ;
2012-05-28 01:29:43 +00:00
return ;
}
2013-12-29 23:35:42 +00:00
2013-11-27 23:35:32 +00:00
_currAviWriter . CloseFile ( ) ;
_currAviWriter . Dispose ( ) ;
_currAviWriter = null ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "A/V capture stopped" ) ;
2013-04-16 00:19:31 +00:00
AVIStatusLabel . Image = Properties . Resources . Blank ;
2013-12-20 22:05:56 +00:00
AVIStatusLabel . ToolTipText = string . Empty ;
2012-09-29 22:37:34 +00:00
AVIStatusLabel . Visible = false ;
2016-12-11 17:14:42 +00:00
_aviSoundInputAsync = null ;
2013-11-27 23:35:32 +00:00
_dumpProxy = null ; // return to normal sound output
sound api changes. added a new ISyncSoundProvider, which works similarly to ISoundProvider except the source (not the sink) determines the number of samples to process. Added facilities to metaspu, dcfilter, speexresampler to work with ISyncSoundProvider. Add ISyncSoundProvider to IEmulator. All IEmulators must provide sync sound, but they need not provide async sound. When async is needed and an IEmulator doesn't provide it, the frontend will wrap it in a vecna metaspu. SNES, GB changed to provide sync sound only. All other emulator cores mostly unchanged; they just provide stub fakesync alongside async, for now. For the moment, the only use of the sync sound is for realtime audio throttling, where it works and sounds quite nice. In the future, sync sound will be supported for AV dumping as well.
2012-10-11 00:44:59 +00:00
RewireSound ( ) ;
2011-07-10 00:04:33 +00:00
}
2011-07-31 22:29:56 +00:00
2013-12-29 23:35:42 +00:00
private void AvFrameAdvance ( )
2012-11-26 21:08:08 +00:00
{
2013-11-27 23:35:32 +00:00
if ( _currAviWriter ! = null )
2012-11-26 21:08:08 +00:00
{
2014-06-02 20:16:59 +00:00
//TODO ZERO - this code is pretty jacked. we'll want to frugalize buffers better for speedier dumping, and we might want to rely on the GL layer for padding
2012-11-26 21:08:08 +00:00
try
{
2015-01-27 04:05:20 +00:00
//is this the best time to handle this? or deeper inside?
if ( _currAviWriterFrameList ! = null )
{
2016-12-04 17:19:34 +00:00
if ( ! _currAviWriterFrameList . Contains ( Emulator . Frame ) )
2015-01-27 04:05:20 +00:00
goto HANDLE_AUTODUMP ;
}
2012-11-26 21:08:08 +00:00
IVideoProvider output ;
2014-06-02 20:16:59 +00:00
IDisposable disposableOutput = null ;
2013-11-27 23:35:32 +00:00
if ( _avwriterResizew > 0 & & _avwriterResizeh > 0 )
2012-11-26 21:08:08 +00:00
{
2014-06-29 02:28:48 +00:00
BitmapBuffer bbin = null ;
2014-06-02 20:16:59 +00:00
Bitmap bmpin = null ;
Bitmap bmpout = null ;
try
2013-12-29 23:35:42 +00:00
{
2014-06-02 20:16:59 +00:00
if ( Global . Config . AVI_CaptureOSD )
2014-02-07 02:28:07 +00:00
{
2014-06-02 20:16:59 +00:00
bbin = CaptureOSD ( ) ;
2014-02-07 02:28:07 +00:00
}
else
{
2016-12-07 19:21:18 +00:00
bbin = new BitmapBuffer ( _currentVideoProvider . BufferWidth , _currentVideoProvider . BufferHeight , _currentVideoProvider . GetVideoBuffer ( ) ) ;
2014-02-07 02:28:07 +00:00
}
2013-12-29 23:35:42 +00:00
2015-10-25 21:06:39 +00:00
bbin . DiscardAlpha ( ) ;
2014-06-02 20:16:59 +00:00
bmpout = new Bitmap ( _avwriterResizew , _avwriterResizeh , PixelFormat . Format32bppArgb ) ;
bmpin = bbin . ToSysdrawingBitmap ( ) ;
using ( var g = Graphics . FromImage ( bmpout ) )
{
if ( _avwriterpad )
{
2016-12-07 19:21:18 +00:00
g . Clear ( Color . FromArgb ( _currentVideoProvider . BackgroundColor ) ) ;
2014-06-02 20:16:59 +00:00
g . DrawImageUnscaled ( bmpin , ( bmpout . Width - bmpin . Width ) / 2 , ( bmpout . Height - bmpin . Height ) / 2 ) ;
}
else
{
2014-11-25 19:34:27 +00:00
g . InterpolationMode = System . Drawing . Drawing2D . InterpolationMode . NearestNeighbor ;
g . PixelOffsetMode = System . Drawing . Drawing2D . PixelOffsetMode . Half ;
2014-06-02 20:16:59 +00:00
g . DrawImage ( bmpin , new Rectangle ( 0 , 0 , bmpout . Width , bmpout . Height ) ) ;
}
}
output = new BmpVideoProvider ( bmpout ) ;
disposableOutput = ( IDisposable ) output ;
}
finally
{
if ( bbin ! = null ) bbin . Dispose ( ) ;
if ( bmpin ! = null ) bmpin . Dispose ( ) ;
}
2012-11-26 21:08:08 +00:00
}
else
{
2014-06-02 20:16:59 +00:00
if ( Global . Config . AVI_CaptureOSD )
{
output = new BitmapBufferVideoProvider ( CaptureOSD ( ) ) ;
disposableOutput = ( IDisposable ) output ;
}
else
2016-12-07 19:21:18 +00:00
output = _currentVideoProvider ;
2012-11-26 21:08:08 +00:00
}
2016-12-04 17:19:34 +00:00
_currAviWriter . SetFrame ( Emulator . Frame ) ;
2014-10-11 03:33:09 +00:00
short [ ] samp ;
int nsamp ;
if ( _dumpaudiosync )
{
2016-12-11 17:14:42 +00:00
( _currAviWriter as VideoStretcher ) . DumpAV ( output , _currentSoundProvider , out samp , out nsamp ) ;
2014-10-11 03:33:09 +00:00
}
else
{
2016-12-11 17:14:42 +00:00
( _currAviWriter as AudioStretcher ) . DumpAV ( output , _aviSoundInputAsync , out samp , out nsamp ) ;
2014-10-11 03:33:09 +00:00
}
2014-06-02 20:16:59 +00:00
if ( disposableOutput ! = null )
2013-12-29 23:35:42 +00:00
{
2014-06-02 20:16:59 +00:00
disposableOutput . Dispose ( ) ;
2013-12-29 23:35:42 +00:00
}
2012-11-26 21:08:08 +00:00
2016-12-12 03:37:28 +00:00
_dumpProxy . PutSamples ( samp , nsamp ) ;
2012-11-26 21:08:08 +00:00
}
catch ( Exception e )
{
2013-04-16 00:19:31 +00:00
MessageBox . Show ( "Video dumping died:\n\n" + e ) ;
2014-01-10 16:54:53 +00:00
AbortAv ( ) ;
2012-11-26 21:08:08 +00:00
}
2015-01-27 04:05:20 +00:00
HANDLE_AUTODUMP :
2013-11-27 23:35:32 +00:00
if ( _autoDumpLength > 0 )
2013-11-03 02:51:21 +00:00
{
2013-11-27 23:35:32 +00:00
_autoDumpLength - - ;
if ( _autoDumpLength = = 0 ) // finish
2013-11-03 02:51:21 +00:00
{
2014-01-10 16:54:53 +00:00
StopAv ( ) ;
if ( _autoCloseOnDump )
2013-11-03 02:51:21 +00:00
{
2013-11-27 23:35:32 +00:00
_exit = true ;
2013-11-03 02:51:21 +00:00
}
}
}
}
}
2014-01-10 16:54:53 +00:00
private int? LoadArhiveChooser ( HawkFile file )
{
var ac = new ArchiveChooser ( file ) ;
if ( ac . ShowDialog ( this ) = = DialogResult . OK )
{
return ac . SelectedMemberIndex ;
}
else
{
return null ;
}
}
2013-11-03 02:51:21 +00:00
#endregion
#region Scheduled for refactor
2013-12-20 22:05:56 +00:00
private void ShowMessageCoreComm ( string message )
2013-12-10 17:58:12 +00:00
{
MessageBox . Show ( this , message , "Warning" , MessageBoxButtons . OK , MessageBoxIcon . Warning ) ;
}
2013-12-25 19:09:53 +00:00
private void ShowLoadError ( object sender , RomLoader . RomErrorArgs e )
2013-11-03 02:51:21 +00:00
{
2014-07-31 21:15:07 +00:00
if ( e . Type = = RomLoader . LoadErrorType . MissingFirmware )
{
var result = MessageBox . Show (
"You are missing the needed firmware files to load this Rom\n\nWould you like to open the firmware manager now and configure your firmwares?" ,
e . Message ,
MessageBoxButtons . YesNo ,
MessageBoxIcon . Error ) ;
if ( result = = DialogResult . Yes )
{
2015-07-12 19:30:26 +00:00
FirmwaresMenuItem_Click ( null , e ) ;
if ( e . Retry )
{
// Retry loading the ROM here. This leads to recursion, as the original call to LoadRom has not exited yet,
// but unless the user tries and fails to set his firmware a lot of times, nothing should happen.
// Refer to how RomLoader implemented its LoadRom method for a potential fix on this.
2015-11-06 14:31:50 +00:00
LoadRom ( e . RomPath , CurrentLoadRomArgs ) ;
2015-07-12 19:30:26 +00:00
}
2014-07-31 21:15:07 +00:00
}
}
else
{
string title = "load error" ;
if ( e . AttemptedCoreLoad ! = null )
{
title = e . AttemptedCoreLoad + " load error" ;
}
2014-05-08 03:18:00 +00:00
2014-07-31 21:15:07 +00:00
MessageBox . Show ( this , e . Message , title , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
}
2013-12-25 19:09:53 +00:00
}
2013-11-03 02:51:21 +00:00
2014-03-18 03:03:53 +00:00
private void NotifyCoreComm ( string message )
{
GlobalWin . OSD . AddMessage ( message ) ;
}
2014-04-14 01:59:57 +00:00
private string ChoosePlatformForRom ( RomGame rom )
{
2014-04-14 12:25:57 +00:00
var platformChooser = new PlatformChooser
2014-04-14 01:59:57 +00:00
{
RomGame = rom
} ;
platformChooser . ShowDialog ( ) ;
return platformChooser . PlatformChoice ;
}
2015-11-06 14:31:50 +00:00
public class LoadRomArgs
{
public bool? Deterministic ;
public IOpenAdvanced OpenAdvanced ;
}
LoadRomArgs CurrentLoadRomArgs ;
2013-12-25 19:09:53 +00:00
// Still needs a good bit of refactoring
2015-11-12 23:47:39 +00:00
public bool LoadRom ( string path , LoadRomArgs args )
2013-12-25 19:09:53 +00:00
{
2015-11-06 14:31:50 +00:00
//default args
if ( args = = null ) args = new LoadRomArgs ( ) ;
//if this is the first call to LoadRom (they will come in recursively) then stash the args
bool firstCall = false ;
if ( CurrentLoadRomArgs = = null )
2014-01-01 19:07:23 +00:00
{
2015-11-06 14:31:50 +00:00
firstCall = true ;
CurrentLoadRomArgs = args ;
}
else
{
args = CurrentLoadRomArgs ;
2014-01-01 19:07:23 +00:00
}
2015-11-06 14:31:50 +00:00
try
{
// If deterministic emulation is passed in, respect that value regardless, else determine a good value (currently that simply means movies require deterministic emulaton)
bool deterministic = args . Deterministic . HasValue ?
args . Deterministic . Value :
Global . MovieSession . QueuedMovie ! = null ;
//Global.MovieSession.Movie.IsActive;
if ( ! GlobalWin . Tools . AskSave ( ) )
{
return false ;
}
bool asLibretro = ( args . OpenAdvanced is OpenAdvanced_Libretro | | args . OpenAdvanced is OpenAdvanced_LibretroNoGame ) ;
var loader = new RomLoader
2013-12-26 01:00:44 +00:00
{
ChooseArchive = LoadArhiveChooser ,
2014-05-24 22:06:08 +00:00
ChoosePlatform = ChoosePlatformForRom ,
2014-08-02 02:41:12 +00:00
Deterministic = deterministic ,
2015-11-06 14:31:50 +00:00
MessageCallback = GlobalWin . OSD . AddMessage ,
AsLibretro = asLibretro
2013-12-26 01:00:44 +00:00
} ;
2015-11-06 14:31:50 +00:00
Global . FirmwareManager . RecentlyServed . Clear ( ) ;
loader . OnLoadError + = ShowLoadError ;
loader . OnLoadSettings + = CoreSettings ;
loader . OnLoadSyncSettings + = CoreSyncSettings ;
// this also happens in CloseGame(). but it needs to happen here since if we're restarting with the same core,
// any settings changes that we made need to make it back to config before we try to instantiate that core with
// the new settings objects
CommitCoreSettingsToConfig ( ) ; // adelikat: I Think by reordering things, this isn't necessary anymore
CloseGame ( ) ;
var nextComm = CreateCoreComm ( ) ;
//we need to inform LoadRom which Libretro core to use...
IOpenAdvanced ioa = args . OpenAdvanced ;
if ( ioa is IOpenAdvancedLibretro )
{
var ioaretro = ioa as IOpenAdvancedLibretro ;
2015-11-08 21:57:54 +00:00
2015-11-06 14:31:50 +00:00
//prepare a core specification
//if it wasnt already specified, use the current default
if ( ioaretro . CorePath = = null ) ioaretro . CorePath = Global . Config . LibretroCore ;
nextComm . LaunchLibretroCore = ioaretro . CorePath ;
if ( nextComm . LaunchLibretroCore = = null )
throw new InvalidOperationException ( "Can't load a file via Libretro until a core is specified" ) ;
}
2015-02-22 20:06:30 +00:00
CoreFileProvider . SyncCoreCommInputSignals ( nextComm ) ;
2015-11-06 14:31:50 +00:00
var result = loader . LoadRom ( path , nextComm ) ;
2012-07-12 23:13:22 +00:00
2015-11-06 14:31:50 +00:00
//we need to replace the path in the OpenAdvanced with the canonical one the user chose.
//It can't be done until loder.LoadRom happens (for CanonicalFullPath)
//i'm not sure this needs to be more abstractly engineered yet until we have more OpenAdvanced examples
if ( ioa is OpenAdvanced_Libretro )
2015-02-07 14:30:14 +00:00
{
2015-11-06 14:31:50 +00:00
var oaretro = ioa as OpenAdvanced_Libretro ;
oaretro . token . Path = loader . CanonicalFullPath ;
2015-02-07 14:30:14 +00:00
}
2015-11-06 14:31:50 +00:00
if ( ioa is OpenAdvanced_OpenRom ) ( ( OpenAdvanced_OpenRom ) ioa ) . Path = loader . CanonicalFullPath ;
string loaderName = "*" + OpenAdvancedSerializer . Serialize ( ioa ) ;
2015-02-07 14:30:14 +00:00
2015-11-06 14:31:50 +00:00
if ( result )
2013-11-03 02:51:21 +00:00
{
2016-12-04 17:19:34 +00:00
Emulator = loader . LoadedEmulator ;
2015-11-06 14:31:50 +00:00
Global . Game = loader . Game ;
CoreFileProvider . SyncCoreCommInputSignals ( nextComm ) ;
InputManager . SyncControls ( ) ;
2016-12-04 17:19:34 +00:00
if ( Emulator is TI83 & & Global . Config . TI83autoloadKeyPad )
2013-12-20 22:05:56 +00:00
{
2015-11-06 14:31:50 +00:00
GlobalWin . Tools . Load < TI83KeyPad > ( ) ;
2013-12-20 22:05:56 +00:00
}
2015-11-06 14:31:50 +00:00
if ( loader . LoadedEmulator is NES )
2014-07-23 02:48:55 +00:00
{
2015-11-06 14:31:50 +00:00
var nes = loader . LoadedEmulator as NES ;
if ( ! string . IsNullOrWhiteSpace ( nes . GameName ) )
{
Global . Game . Name = nes . GameName ;
}
Global . Game . Status = nes . RomStatus ;
2014-07-23 02:48:55 +00:00
}
2015-11-06 14:31:50 +00:00
else if ( loader . LoadedEmulator is QuickNES )
2014-07-23 02:48:55 +00:00
{
2015-11-06 14:31:50 +00:00
var qns = loader . LoadedEmulator as QuickNES ;
if ( ! string . IsNullOrWhiteSpace ( qns . BootGodName ) )
{
Global . Game . Name = qns . BootGodName ;
}
if ( qns . BootGodStatus . HasValue )
{
Global . Game . Status = qns . BootGodStatus . Value ;
}
2014-07-23 02:48:55 +00:00
}
2012-09-29 23:03:51 +00:00
2015-11-06 14:31:50 +00:00
Global . Rewinder . ResetRewindBuffer ( ) ;
2012-09-30 00:53:08 +00:00
2016-12-04 17:19:34 +00:00
if ( Emulator . CoreComm . RomStatusDetails = = null & & loader . Rom ! = null )
2015-11-06 14:31:50 +00:00
{
2016-12-04 17:19:34 +00:00
Emulator . CoreComm . RomStatusDetails = string . Format (
2015-11-06 14:31:50 +00:00
"{0}\r\nSHA1:{1}\r\nMD5:{2}\r\n" ,
loader . Game . Name ,
loader . Rom . RomData . HashSHA1 ( ) ,
loader . Rom . RomData . HashMD5 ( ) ) ;
}
2012-10-28 23:38:41 +00:00
2016-12-04 17:19:34 +00:00
if ( Emulator . BoardName ! = null )
2015-11-06 14:31:50 +00:00
{
2016-12-04 17:19:34 +00:00
Console . WriteLine ( "Core reported BoardID: \"{0}\"" , Emulator . BoardName ) ;
2015-11-06 14:31:50 +00:00
}
2013-11-03 02:51:21 +00:00
2015-11-06 14:31:50 +00:00
// restarts the lua console if a different rom is loaded.
// im not really a fan of how this is done..
if ( Global . Config . RecentRoms . Empty | | Global . Config . RecentRoms . MostRecent ! = loaderName )
{
GlobalWin . Tools . Restart < LuaConsole > ( ) ;
}
2012-11-26 23:16:31 +00:00
2015-11-06 14:31:50 +00:00
Global . Config . RecentRoms . Add ( loaderName ) ;
JumpLists . AddRecentItem ( loaderName , ioa . DisplayName ) ;
2014-08-02 15:32:48 +00:00
2015-11-06 14:31:50 +00:00
// Don't load Save Ram if a movie is being loaded
if ( ! Global . MovieSession . MovieIsQueued & & File . Exists ( PathManager . SaveRamPath ( loader . Game ) ) )
{
LoadSaveRam ( ) ;
}
2013-12-20 22:05:56 +00:00
2015-11-06 14:31:50 +00:00
GlobalWin . Tools . Restart ( ) ;
2013-03-10 23:03:52 +00:00
2015-11-06 14:31:50 +00:00
if ( Global . Config . LoadCheatFileByGame )
2013-11-03 02:51:21 +00:00
{
2016-10-06 18:57:39 +00:00
Global . CheatList . SetDefaultFileName ( ToolManager . GenerateDefaultCheatFilename ( ) ) ;
2015-11-06 14:31:50 +00:00
if ( Global . CheatList . AttemptToLoadCheatFile ( ) )
{
GlobalWin . OSD . AddMessage ( "Cheats file loaded" ) ;
}
2016-10-06 18:57:39 +00:00
else if ( Global . CheatList . Any ( ) )
{
Global . CheatList . Clear ( ) ;
}
2013-11-03 02:51:21 +00:00
}
2013-07-27 01:03:15 +00:00
2015-11-06 14:31:50 +00:00
SetWindowText ( ) ;
2016-02-28 17:15:23 +00:00
CurrentlyOpenRomPoopForAdvancedLoaderPleaseRefactorME = loaderName ;
CurrentlyOpenRom = loaderName . Replace ( "*OpenRom*" , "" ) ; // POOP
2015-11-06 14:31:50 +00:00
HandlePlatformMenus ( ) ;
_stateSlots . Clear ( ) ;
UpdateCoreStatusBarButton ( ) ;
UpdateDumpIcon ( ) ;
SetMainformMovieInfo ( ) ;
CurrentlyOpenRomArgs = args ;
2013-10-11 16:32:36 +00:00
2015-11-06 14:31:50 +00:00
Global . Rewinder . CaptureRewindState ( ) ;
2013-10-27 07:54:00 +00:00
2015-11-06 14:31:50 +00:00
Global . StickyXORAdapter . ClearStickies ( ) ;
Global . StickyXORAdapter . ClearStickyFloats ( ) ;
Global . AutofireStickyXORAdapter . ClearStickies ( ) ;
2013-10-27 07:54:00 +00:00
2015-11-06 14:31:50 +00:00
RewireSound ( ) ;
2016-01-31 01:24:30 +00:00
ToolFormBase . UpdateCheatRelatedTools ( null , null ) ;
2015-11-06 14:31:50 +00:00
if ( Global . Config . AutoLoadLastSaveSlot & & _stateSlots . HasSlot ( Global . Config . SaveSlot ) )
{
LoadQuickSave ( "QuickSave" + Global . Config . SaveSlot ) ;
}
2015-02-05 23:25:28 +00:00
2015-11-06 14:31:50 +00:00
if ( Global . FirmwareManager . RecentlyServed . Count > 0 )
{
Console . WriteLine ( "Active Firmwares:" ) ;
foreach ( var f in Global . FirmwareManager . RecentlyServed )
{
Console . WriteLine ( " {0} : {1}" , f . FirmwareId , f . Hash ) ;
}
}
2016-03-16 22:06:53 +00:00
ApiHawk . ClientApi . OnRomLoaded ( ) ;
2015-11-06 14:31:50 +00:00
return true ;
}
else
2015-02-05 23:25:28 +00:00
{
2016-09-29 04:16:24 +00:00
//This shows up if there's a problem
2015-11-06 14:31:50 +00:00
// TODO: put all these in a single method or something
//The ROM has been loaded by a recursive invocation of the LoadROM method.
2016-12-04 17:19:34 +00:00
if ( ! ( Emulator is NullEmulator ) )
2015-02-05 23:25:28 +00:00
{
2016-03-16 22:06:53 +00:00
ApiHawk . ClientApi . OnRomLoaded ( ) ;
2015-11-06 14:31:50 +00:00
return true ;
2015-02-05 23:25:28 +00:00
}
2015-11-06 14:31:50 +00:00
HandlePlatformMenus ( ) ;
_stateSlots . Clear ( ) ;
UpdateStatusSlots ( ) ;
UpdateCoreStatusBarButton ( ) ;
UpdateDumpIcon ( ) ;
SetMainformMovieInfo ( ) ;
SetWindowText ( ) ;
return false ;
2014-07-21 22:38:53 +00:00
}
2013-10-27 07:54:00 +00:00
}
2015-11-06 14:31:50 +00:00
finally
2013-12-25 19:09:53 +00:00
{
2015-11-06 14:31:50 +00:00
if ( firstCall )
2015-07-12 19:30:26 +00:00
{
2015-11-06 14:31:50 +00:00
CurrentLoadRomArgs = null ;
2015-07-12 19:30:26 +00:00
}
2013-12-25 19:09:53 +00:00
}
}
2016-02-28 17:15:23 +00:00
private string CurrentlyOpenRomPoopForAdvancedLoaderPleaseRefactorME = "" ;
2016-12-04 17:19:34 +00:00
private void CommitCoreSettingsToConfig ( )
2013-10-27 07:54:00 +00:00
{
2015-12-07 17:04:30 +00:00
// save settings object
2016-12-04 17:19:34 +00:00
var t = Emulator . GetType ( ) ;
var settable = new SettingsAdapter ( Emulator ) ;
2015-12-07 17:04:30 +00:00
if ( settable . HasSettings )
2013-10-27 07:54:00 +00:00
{
2015-12-07 17:04:30 +00:00
Global . Config . PutCoreSettings ( settable . GetSettings ( ) , t ) ;
2013-10-27 07:54:00 +00:00
}
2015-12-07 17:04:30 +00:00
if ( settable . HasSyncSettings & & ! Global . MovieSession . Movie . IsActive )
2015-12-05 09:09:39 +00:00
{
2015-12-07 17:04:30 +00:00
// don't trample config with loaded-from-movie settings
Global . Config . PutCoreSyncSettings ( settable . GetSyncSettings ( ) , t ) ;
2015-12-05 09:09:39 +00:00
}
2015-12-07 17:04:30 +00:00
}
2013-12-23 23:03:12 +00:00
2013-12-20 22:05:56 +00:00
// whats the difference between these two methods??
// its very tricky. rename to be more clear or combine them.
2014-10-19 01:22:47 +00:00
// This gets called whenever a core related thing is changed.
// Like reboot core.
2013-11-27 23:35:32 +00:00
private void CloseGame ( bool clearSram = false )
2013-10-27 15:23:41 +00:00
{
2014-10-20 00:31:05 +00:00
GameIsClosing = true ;
2013-11-27 23:35:32 +00:00
if ( clearSram )
2013-10-27 15:23:41 +00:00
{
2013-11-27 23:35:32 +00:00
var path = PathManager . SaveRamPath ( Global . Game ) ;
2013-11-03 02:51:21 +00:00
if ( File . Exists ( path ) )
2013-10-27 15:23:41 +00:00
{
2013-11-03 02:51:21 +00:00
File . Delete ( path ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "SRAM cleared." ) ;
2013-10-27 15:23:41 +00:00
}
}
2016-12-04 17:19:34 +00:00
else if ( Emulator . HasSaveRam ( ) & & Emulator . AsSaveRam ( ) . SaveRamModified )
2013-11-03 02:51:21 +00:00
{
SaveRam ( ) ;
}
2013-12-29 23:35:42 +00:00
StopAv ( ) ;
2013-12-22 00:44:39 +00:00
2013-12-23 23:03:12 +00:00
CommitCoreSettingsToConfig ( ) ;
2014-08-02 15:32:48 +00:00
if ( Global . MovieSession . Movie . IsActive ) // Note: this must be called after CommitCoreSettingsToConfig()
{
StopMovie ( true ) ;
}
2015-01-27 22:23:56 +00:00
2016-08-22 18:57:18 +00:00
if ( GlobalWin . Tools . IsLoaded < TraceLogger > ( ) )
GlobalWin . Tools . Get < TraceLogger > ( ) . Restart ( ) ;
2015-01-27 22:23:56 +00:00
Global . CheatList . SaveOnClose ( ) ;
2016-12-04 17:19:34 +00:00
Emulator . Dispose ( ) ;
2015-02-22 20:06:30 +00:00
var coreComm = CreateCoreComm ( ) ;
CoreFileProvider . SyncCoreCommInputSignals ( coreComm ) ;
2016-12-04 17:19:34 +00:00
Emulator = new NullEmulator ( coreComm , Global . Config . GetCoreSettings < NullEmulator > ( ) ) ;
2015-02-22 20:38:10 +00:00
Global . ActiveController = new Controller ( NullEmulator . NullController ) ;
2013-11-03 02:51:21 +00:00
Global . AutoFireController = Global . AutofireNullControls ;
2014-07-17 22:27:33 +00:00
RewireSound ( ) ;
2013-11-03 02:51:21 +00:00
RebootStatusBarIcon . Visible = false ;
2014-10-20 00:31:05 +00:00
GameIsClosing = false ;
2013-10-27 15:23:41 +00:00
}
2015-07-12 19:30:26 +00:00
public bool GameIsClosing { get ; set ; } // Lets tools make better decisions when being called by CloseGame
2014-10-20 00:31:05 +00:00
2013-11-27 23:35:32 +00:00
public void CloseRom ( bool clearSram = false )
2013-10-27 15:23:41 +00:00
{
2014-10-19 01:22:47 +00:00
//This gets called after Close Game gets called.
//Tested with NESHawk and SMB3 (U)
2013-11-05 16:37:05 +00:00
if ( GlobalWin . Tools . AskSave ( ) )
{
2013-11-27 23:35:32 +00:00
CloseGame ( clearSram ) ;
2015-02-22 20:06:30 +00:00
var coreComm = CreateCoreComm ( ) ;
CoreFileProvider . SyncCoreCommInputSignals ( coreComm ) ;
2016-12-04 17:19:34 +00:00
Emulator = new NullEmulator ( coreComm , Global . Config . GetCoreSettings < NullEmulator > ( ) ) ;
2014-07-21 22:21:52 +00:00
Global . Game = GameInfo . NullInstance ;
2013-11-03 02:51:21 +00:00
2013-11-05 16:37:05 +00:00
GlobalWin . Tools . Restart ( ) ;
RewireSound ( ) ;
2013-12-27 01:19:38 +00:00
Global . Rewinder . ResetRewindBuffer ( ) ;
2014-06-04 17:02:54 +00:00
Text = "BizHawk" + ( VersionInfo . DeveloperBuild ? " (interim) " : string . Empty ) ;
2013-11-05 16:37:05 +00:00
HandlePlatformMenus ( ) ;
2013-11-27 23:35:32 +00:00
_stateSlots . Clear ( ) ;
2013-11-05 16:37:05 +00:00
UpdateDumpIcon ( ) ;
2014-04-25 01:19:57 +00:00
UpdateCoreStatusBarButton ( ) ;
2014-07-26 15:31:36 +00:00
ClearHolds ( ) ;
2014-07-27 17:49:25 +00:00
PauseOnFrame = null ;
2016-01-31 01:24:30 +00:00
ToolFormBase . UpdateCheatRelatedTools ( null , null ) ;
2014-12-05 00:52:16 +00:00
UpdateStatusSlots ( ) ;
2015-11-06 14:31:50 +00:00
CurrentlyOpenRom = null ;
CurrentlyOpenRomArgs = null ;
2013-11-05 16:37:05 +00:00
}
2013-10-27 15:23:41 +00:00
}
2013-11-01 15:47:37 +00:00
2014-06-08 19:36:33 +00:00
private static void ShowConversionError ( string errorMsg )
2013-11-01 18:52:26 +00:00
{
2014-06-08 19:36:33 +00:00
MessageBox . Show ( errorMsg , "Conversion error" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
}
2013-11-01 18:52:26 +00:00
2014-06-19 02:30:22 +00:00
private static void ProcessMovieImport ( string fn )
2014-06-08 19:36:33 +00:00
{
MovieImport . ProcessMovieImport ( fn , ShowConversionError , GlobalWin . OSD . AddMessage ) ;
2013-11-03 02:51:21 +00:00
}
2014-07-11 17:14:45 +00:00
public void EnableRewind ( bool enabled )
{
if ( enabled )
{
Global . Rewinder . RewindActive = true ;
GlobalWin . OSD . AddMessage ( "Rewind enabled" ) ;
}
else
{
Global . Rewinder . RewindActive = false ;
GlobalWin . OSD . AddMessage ( "Rewind suspended" ) ;
}
}
2014-09-27 12:19:50 +00:00
public void ClearRewindData ( )
{
Global . Rewinder . ResetRewindBuffer ( ) ;
}
2013-11-03 02:51:21 +00:00
#endregion
2014-05-12 17:24:43 +00:00
2014-10-19 01:22:47 +00:00
#region Tool Control API
2014-08-19 19:24:17 +00:00
2014-10-19 01:22:47 +00:00
// TODO: move me
public IControlMainform master { get ; private set ; }
2015-12-07 17:04:30 +00:00
2014-07-08 16:08:52 +00:00
public void RelinquishControl ( IControlMainform master )
{
2014-08-19 19:24:17 +00:00
this . master = master ;
}
2015-12-07 18:43:32 +00:00
private bool IsSlave
{
get { return master ! = null ; }
}
public void TakeBackControl ( )
{
master = null ;
}
2015-12-07 17:04:30 +00:00
private int SlotToInt ( string slot )
{
return int . Parse ( slot . Substring ( slot . Length - 1 , 1 ) ) ;
}
public void LoadState ( string path , string userFriendlyStateName , bool fromLua = false , bool supressOSD = false ) // Move to client.common
{
2016-12-04 17:19:34 +00:00
if ( ! Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
return ;
}
if ( IsSlave & & master . WantsToControlSavestates )
{
master . LoadState ( ) ;
return ;
}
// If from lua, disable counting rerecords
bool wasCountingRerecords = Global . MovieSession . Movie . IsCountingRerecords ;
if ( fromLua )
Global . MovieSession . Movie . IsCountingRerecords = false ;
if ( SavestateManager . LoadStateFile ( path , userFriendlyStateName ) )
{
2016-09-22 14:13:26 +00:00
GlobalWin . OSD . ClearGUIText ( ) ;
2016-05-29 14:50:16 +00:00
ClientApi . OnStateLoaded ( this , userFriendlyStateName ) ;
2016-02-16 00:17:19 +00:00
if ( GlobalWin . Tools . Has < LuaConsole > ( ) )
{
GlobalWin . Tools . LuaConsole . LuaImp . CallLoadStateEvent ( userFriendlyStateName ) ;
}
2015-12-07 17:04:30 +00:00
SetMainformMovieInfo ( ) ;
GlobalWin . Tools . UpdateToolsBefore ( fromLua ) ;
UpdateToolsAfter ( fromLua ) ;
UpdateToolsLoadstate ( ) ;
Global . AutoFireController . ClearStarts ( ) ;
if ( ! supressOSD )
{
GlobalWin . OSD . AddMessage ( "Loaded state: " + userFriendlyStateName ) ;
}
}
else
{
GlobalWin . OSD . AddMessage ( "Loadstate error!" ) ;
}
Global . MovieSession . Movie . IsCountingRerecords = wasCountingRerecords ;
}
public void LoadQuickSave ( string quickSlotName , bool fromLua = false , bool supressOSD = false )
{
2016-12-04 17:19:34 +00:00
if ( ! Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
return ;
}
2016-05-29 14:50:16 +00:00
bool handled ;
ClientApi . OnBeforeQuickLoad ( this , quickSlotName , out handled ) ;
if ( handled )
{
return ;
}
2015-12-07 17:04:30 +00:00
if ( IsSlave & & master . WantsToControlSavestates )
{
master . LoadQuickSave ( SlotToInt ( quickSlotName ) ) ;
return ;
}
var path = PathManager . SaveStatePrefix ( Global . Game ) + "." + quickSlotName + ".State" ;
if ( File . Exists ( path ) = = false )
{
GlobalWin . OSD . AddMessage ( "Unable to load " + quickSlotName + ".State" ) ;
return ;
}
LoadState ( path , quickSlotName , fromLua , supressOSD ) ;
}
public void SaveState ( string path , string userFriendlyStateName , bool fromLua )
{
2016-12-04 17:19:34 +00:00
if ( ! Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
return ;
}
if ( IsSlave & & master . WantsToControlSavestates )
{
master . SaveState ( ) ;
return ;
}
try
{
SavestateManager . SaveStateFile ( path , userFriendlyStateName ) ;
2016-05-29 14:50:16 +00:00
ClientApi . OnStateSaved ( this , userFriendlyStateName ) ;
2015-12-07 17:04:30 +00:00
GlobalWin . OSD . AddMessage ( "Saved state: " + userFriendlyStateName ) ;
}
catch ( IOException )
{
GlobalWin . OSD . AddMessage ( "Unable to save state " + path ) ;
}
if ( ! fromLua )
{
UpdateStatusSlots ( ) ;
}
}
// TODO: should backup logic be stuffed in into Client.Common.SaveStateManager?
public void SaveQuickSave ( string quickSlotName )
{
2016-12-04 17:19:34 +00:00
if ( ! Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
return ;
}
2016-05-29 14:50:16 +00:00
bool handled ;
ClientApi . OnBeforeQuickSave ( this , quickSlotName , out handled ) ;
if ( handled )
{
return ;
}
2015-12-07 17:04:30 +00:00
if ( IsSlave & & master . WantsToControlSavestates )
{
master . SaveQuickSave ( SlotToInt ( quickSlotName ) ) ;
return ;
}
var path = PathManager . SaveStatePrefix ( Global . Game ) + "." + quickSlotName + ".State" ;
var file = new FileInfo ( path ) ;
if ( file . Directory ! = null & & file . Directory . Exists = = false )
{
file . Directory . Create ( ) ;
}
// Make backup first
2016-02-27 22:19:33 +00:00
if ( Global . Config . BackupSavestates )
BizHawk . Common . Util . TryMoveBackupFile ( path , path + ".bak" ) ;
2015-12-07 17:04:30 +00:00
SaveState ( path , quickSlotName , false ) ;
if ( GlobalWin . Tools . Has < LuaConsole > ( ) )
{
GlobalWin . Tools . LuaConsole . LuaImp . CallSaveStateEvent ( quickSlotName ) ;
}
}
private void SaveStateAs ( )
{
2016-12-04 17:19:34 +00:00
if ( ! Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
return ;
}
if ( IsSlave & & master . WantsToControlSavestates )
{
master . SaveStateAs ( ) ;
return ;
}
var path = PathManager . GetSaveStatePath ( Global . Game ) ;
var file = new FileInfo ( path ) ;
if ( file . Directory ! = null & & file . Directory . Exists = = false )
{
file . Directory . Create ( ) ;
}
var sfd = new SaveFileDialog
{
AddExtension = true ,
DefaultExt = "State" ,
Filter = "Save States (*.State)|*.State|All Files|*.*" ,
InitialDirectory = path ,
FileName = PathManager . SaveStatePrefix ( Global . Game ) + "." + "QuickSave0.State"
} ;
var result = sfd . ShowHawkDialog ( ) ;
if ( result = = DialogResult . OK )
{
SaveState ( sfd . FileName , sfd . FileName , false ) ;
}
}
private void LoadStateAs ( )
{
2016-12-04 17:19:34 +00:00
if ( ! Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
return ;
}
if ( IsSlave & & master . WantsToControlSavestates )
{
master . LoadStateAs ( ) ;
return ;
}
var ofd = new OpenFileDialog
{
InitialDirectory = PathManager . GetSaveStatePath ( Global . Game ) ,
Filter = "Save States (*.State)|*.State|All Files|*.*" ,
RestoreDirectory = true
} ;
var result = ofd . ShowHawkDialog ( ) ;
if ( result ! = DialogResult . OK )
{
return ;
}
if ( File . Exists ( ofd . FileName ) = = false )
{
return ;
}
LoadState ( ofd . FileName , Path . GetFileName ( ofd . FileName ) ) ;
}
private void SelectSlot ( int slot )
{
2016-12-04 17:19:34 +00:00
if ( Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
if ( IsSlave & & master . WantsToControlSavestates )
{
master . SelectSlot ( slot ) ;
return ;
}
Global . Config . SaveSlot = slot ;
SaveSlotSelectedMessage ( ) ;
UpdateStatusSlots ( ) ;
}
}
private void PreviousSlot ( )
{
2016-12-04 17:19:34 +00:00
if ( Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
if ( IsSlave & & master . WantsToControlSavestates )
{
master . PreviousSlot ( ) ;
return ;
}
if ( Global . Config . SaveSlot = = 0 )
{
Global . Config . SaveSlot = 9 ; // Wrap to end of slot list
}
else if ( Global . Config . SaveSlot > 9 )
{
Global . Config . SaveSlot = 9 ; // Meh, just in case
}
else
{
Global . Config . SaveSlot - - ;
}
SaveSlotSelectedMessage ( ) ;
UpdateStatusSlots ( ) ;
}
}
private void NextSlot ( )
{
2016-12-04 17:19:34 +00:00
if ( Emulator . HasSavestates ( ) )
2015-12-07 17:04:30 +00:00
{
if ( IsSlave & & master . WantsToControlSavestates )
{
master . NextSlot ( ) ;
return ;
}
if ( Global . Config . SaveSlot > = 9 )
{
Global . Config . SaveSlot = 0 ; // Wrap to beginning of slot list
}
else if ( Global . Config . SaveSlot < 0 )
{
Global . Config . SaveSlot = 0 ; // Meh, just in case
}
else
{
Global . Config . SaveSlot + + ;
}
SaveSlotSelectedMessage ( ) ;
UpdateStatusSlots ( ) ;
}
}
2014-10-19 01:22:47 +00:00
private void ToggleReadOnly ( )
{
if ( IsSlave & & master . WantsToControlReadOnly )
{
master . ToggleReadOnly ( ) ;
}
else
{
if ( Global . MovieSession . Movie . IsActive )
{
Global . MovieSession . ReadOnly ^ = true ;
GlobalWin . OSD . AddMessage ( Global . MovieSession . ReadOnly ? "Movie read-only mode" : "Movie read+write mode" ) ;
}
else
{
GlobalWin . OSD . AddMessage ( "No movie active" ) ;
}
}
}
public void StopMovie ( bool saveChanges = true )
{
if ( IsSlave & & master . WantsToControlStopMovie )
{
2014-11-08 17:44:25 +00:00
master . StopMovie ( ! saveChanges ) ;
2014-10-19 01:22:47 +00:00
}
else
{
Global . MovieSession . StopMovie ( saveChanges ) ;
SetMainformMovieInfo ( ) ;
UpdateStatusSlots ( ) ;
}
}
2014-06-28 22:48:07 +00:00
2014-08-13 20:33:59 +00:00
private void GBAcoresettingsToolStripMenuItem1_Click ( object sender , EventArgs e )
{
GenericCoreConfig . DoDialog ( this , "Gameboy Advance Settings" ) ;
2014-10-19 01:22:47 +00:00
}
2014-08-19 19:24:17 +00:00
2014-09-27 12:19:50 +00:00
private void CaptureRewind ( bool suppressCaptureRewind )
{
if ( IsSlave & & master . WantsToControlRewind )
{
master . CaptureRewind ( ) ;
}
else if ( ! suppressCaptureRewind & & Global . Rewinder . RewindActive )
{
Global . Rewinder . CaptureRewindState ( ) ;
}
}
2015-01-31 22:16:02 +00:00
private bool Rewind ( ref bool runFrame , long currentTimestamp )
2014-09-27 12:19:50 +00:00
{
2016-06-13 10:17:21 +00:00
var isRewinding = false ;
2014-09-27 12:19:50 +00:00
if ( IsSlave & & master . WantsToControlRewind )
{
if ( Global . ClientControls [ "Rewind" ] | | PressRewind )
{
2016-06-13 10:17:21 +00:00
if ( _frameRewindTimestamp = = 0 )
{
isRewinding = true ;
_frameRewindTimestamp = currentTimestamp ;
}
else
{
double timestampDeltaMs = ( double ) ( currentTimestamp - _frameRewindTimestamp ) / Stopwatch . Frequency * 1000.0 ;
isRewinding = timestampDeltaMs > = Global . Config . FrameProgressDelayMs ;
}
if ( isRewinding )
{
runFrame = true ; // TODO: the master should be deciding this!
master . Rewind ( ) ;
}
2014-09-27 12:19:50 +00:00
}
2016-06-13 10:17:21 +00:00
else
{
_frameRewindTimestamp = 0 ;
}
return isRewinding ;
2014-09-27 12:19:50 +00:00
}
2015-11-06 14:31:50 +00:00
2014-09-27 12:19:50 +00:00
if ( Global . Rewinder . RewindActive & & ( Global . ClientControls [ "Rewind" ] | | PressRewind )
& & ! Global . MovieSession . Movie . IsRecording ) // Rewind isn't "bulletproof" and can desync a recording movie!
{
2015-01-31 22:16:02 +00:00
if ( EmulatorPaused )
{
if ( _frameRewindTimestamp = = 0 )
{
isRewinding = true ;
_frameRewindTimestamp = currentTimestamp ;
}
else
{
double timestampDeltaMs = ( double ) ( currentTimestamp - _frameRewindTimestamp ) / Stopwatch . Frequency * 1000.0 ;
isRewinding = timestampDeltaMs > = Global . Config . FrameProgressDelayMs ;
}
}
else
{
isRewinding = true ;
}
2014-09-27 12:19:50 +00:00
2015-01-31 22:16:02 +00:00
if ( isRewinding )
{
Global . Rewinder . Rewind ( 1 ) ;
runFrame = Global . Rewinder . Count ! = 0 ;
}
}
else
{
_frameRewindTimestamp = 0 ;
2014-09-27 12:19:50 +00:00
}
return isRewinding ;
}
2014-10-19 01:22:47 +00:00
#endregion
2014-08-23 01:18:59 +00:00
2014-11-23 21:46:28 +00:00
private void FeaturesMenuItem_Click ( object sender , EventArgs e )
{
2015-01-16 00:48:40 +00:00
GlobalWin . Tools . Load < CoreFeatureAnalysis > ( ) ;
2014-11-23 21:46:28 +00:00
}
2015-08-27 01:55:55 +00:00
private void BasicBotMenuItem_Click ( object sender , EventArgs e )
{
GlobalWin . Tools . Load < BasicBot > ( ) ;
}
2015-09-05 20:48:37 +00:00
private void DisplayMessagesMenuItem_Click ( object sender , EventArgs e )
{
Global . Config . DisplayMessages ^ = true ;
}
2015-11-14 12:49:45 +00:00
private void gameSharkConverterToolStripMenuItem_Click ( object sender , EventArgs e )
{
GlobalWin . Tools . Load < GameShark > ( ) ;
}
2014-11-23 21:46:28 +00:00
private void HelpSubMenu_DropDownOpened ( object sender , EventArgs e )
{
FeaturesMenuItem . Visible = VersionInfo . DeveloperBuild ;
}
2015-04-19 21:02:22 +00:00
private void CreateMultigameFileMenuItem_Click ( object sender , EventArgs e )
{
GlobalWin . Tools . Load < MultiDiskBundler > ( ) ;
}
2015-05-08 00:56:46 +00:00
2015-05-09 12:19:55 +00:00
private void coreToolStripMenuItem_DropDownOpened ( object sender , EventArgs e )
{
quickNESToolStripMenuItem . Checked = Global . Config . NES_InQuickNES = = true ;
nesHawkToolStripMenuItem . Checked = Global . Config . NES_InQuickNES = = false ;
}
2016-11-13 01:23:54 +00:00
private void allowGameDBCoreOverridesToolStripMenuItem_Click ( object sender , EventArgs e )
{
Global . Config . CoreForcingViaGameDB ^ = true ;
}
2014-10-19 01:22:47 +00:00
}
2015-11-21 00:03:48 +00:00
}