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 ;
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 ( ) ;
2013-12-21 16:42:36 +00:00
ToolHelpers . 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-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 ) ;
ret . RequestGLContext = ( ) = > GlobalWin . GLManager . CreateGLContext ( ) ;
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 ( ) ;
2013-11-04 15:52:59 +00:00
Global . CheatList . Changed + = ToolHelpers . 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 = ( ) = >
{
2013-12-20 22:05:56 +00:00
using ( var NesCartFile =
new HawkFile ( Path . Combine ( PathManager . GetExeDirectoryAbsolute ( ) , "gamedb" , "NesCarts.7z" ) ) . 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 ;
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=" ) )
{
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-02-22 03:53:07 +00:00
PresentationPanel = new PresentationPanel ( ) ;
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 ( ) )
{
CloseGame ( ) ;
Global . MovieSession . Movie . Stop ( ) ;
GlobalWin . Tools . Close ( ) ;
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 ) ;
Global . 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
2014-08-02 15:32:48 +00:00
LoadRom ( cmdRom ) ;
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 )
{
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
}
else
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
2013-11-10 02:55:11 +00:00
StartNewMovie ( movie , false ) ;
2011-06-30 02:30:06 +00:00
Global . Config . RecentMovies . Add ( cmdMovie ) ;
}
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 )
{
ToggleFullscreen ( ) ;
}
2014-07-21 22:21:52 +00:00
if ( cmdLoadState ! = null & & ! Global . Game . IsNullInstance )
2012-09-03 19:42:53 +00:00
{
2013-12-30 16:49:13 +00:00
LoadQuickSave ( "QuickSave" + cmdLoadState ) ;
2012-09-03 19:42:53 +00:00
}
2014-07-21 22:21:52 +00:00
else if ( Global . Config . AutoLoadLastSaveSlot & & ! Global . Game . IsNullInstance )
2012-09-03 19:42:53 +00:00
{
2013-12-30 16:49:13 +00:00
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
2011-06-11 12:54:26 +00:00
if ( Global . Config . DisplayStatusBar = = false )
2013-09-07 03:15:29 +00:00
{
2013-10-27 15:53:37 +00:00
MainStatusBar . Visible = false ;
2013-09-07 03:15:29 +00:00
}
2011-06-11 12:54:26 +00:00
else
2013-09-07 03:15:29 +00:00
{
2013-10-27 07:54:00 +00:00
DisplayStatusBarMenuItem . Checked = true ;
2013-09-07 03:15:29 +00:00
}
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 ( ) ;
2014-01-27 06:03:18 +00:00
//TODO POOP
2015-02-22 03:53:07 +00:00
PresentationPanel . Control . Paint + = ( o , e ) = >
2013-10-12 15:40:20 +00:00
{
2013-11-03 16:07:58 +00:00
GlobalWin . DisplayManager . NeedsToPaint = true ;
2013-10-14 03:22:33 +00:00
} ;
2011-02-21 09:48:53 +00:00
}
2011-02-20 08:40:22 +00:00
public void ProgramRunLoop ( )
{
2012-02-24 20:38:35 +00:00
CheckMessages ( ) ;
LogConsole . PositionConsole ( ) ;
2014-01-01 03:03:10 +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 (
( Global . 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
2014-04-28 00:39:40 +00:00
if ( Global . Config . DisplayInput ) // Input display wants to update even while paused
{
GlobalWin . DisplayManager . NeedsToPaint = true ;
}
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
2013-12-20 22:05:56 +00:00
if ( GlobalWin . DisplayManager . NeedsToPaint )
{
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
}
2013-12-20 22:05:56 +00:00
2011-02-20 08:40:22 +00:00
Thread . Sleep ( 0 ) ;
}
2011-07-11 07:35:14 +00:00
Shutdown ( ) ;
}
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...
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
}
2013-11-08 15:34:47 +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
2013-11-03 02:51:21 +00:00
public string CurrentlyOpenRom ;
public bool PauseAVI = false ;
public bool PressFrameAdvance = false ;
public bool PressRewind = false ;
public bool FastForward = false ;
public bool TurboFastForward = false ;
public bool RestoreReadWriteOnStop = false ;
public bool UpdateFrame = 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
{
GlobalWin . Tools . UpdateToolsBefore ( ) ;
GlobalWin . Tools . UpdateToolsAfter ( ) ;
}
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>
public bool AllowInput
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
get
2012-09-03 20:17:57 +00:00
{
2013-12-20 22:05:56 +00:00
// the main form gets input
if ( ActiveForm = = this )
{
return true ;
}
2013-11-03 02:51:21 +00:00
2013-12-20 22:05: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 | |
2014-06-22 13:57:23 +00:00
ActiveForm is VirtualpadTool )
2013-12-20 22:05:56 +00:00
{
return true ;
}
// if no form is active on this process, then the background input setting applies
if ( ActiveForm = = null & & Global . Config . AcceptBackgroundInput )
{
return true ;
}
2013-11-03 02:51:21 +00:00
return false ;
2012-09-03 20:17:57 +00:00
}
2012-09-29 22:37:34 +00:00
}
2011-06-19 20:50:46 +00:00
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 ;
2013-11-03 02:51:21 +00:00
for ( ; ; )
{
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
{
2015-01-14 22:37:37 +00:00
var video = Global . Emulator . VideoProvider ( ) ;
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 ) ) ;
2015-01-14 22:37:37 +00:00
float x = P . X / ( float ) video . BufferWidth ;
2014-05-04 14:10:28 +00:00
return new Tuple < string , float > ( "WMouse X" , x * 20000 - 10000 ) ;
}
if ( o . Item1 = = "WMouse Y" )
{
2014-06-29 02:28:48 +00:00
var P = GlobalWin . DisplayManager . UntransformPoint ( new Point ( 0 , ( int ) o . Item2 ) ) ;
2015-01-14 22:37:37 +00:00
float y = P . Y / ( float ) video . BufferHeight ;
2014-05-04 14:10:28 +00:00
return new Tuple < string , float > ( "WMouse Y" , y * 20000 - 10000 ) ;
}
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
{
2014-08-02 15:32:48 +00:00
LoadRom ( CurrentlyOpenRom ) ;
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
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
{
2014-06-02 20:16:59 +00:00
using ( var img = bb . ToSysdrawingBitmap ( ) )
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
2013-11-03 02:51:21 +00:00
public void TakeScreenshot ( )
2011-02-20 08:40:22 +00:00
{
2013-12-20 22:05:56 +00:00
TakeScreenshot (
String . Format ( PathManager . ScreenshotPrefix ( Global . Game ) + ".{0:yyyy-MM-dd HH.mm.ss}.png" , DateTime . Now )
) ;
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 ) )
QuickBmpFile . Save ( Global . Emulator . VideoProvider ( ) , fs , r . Next ( 50 , 500 ) , r . Next ( 50 , 500 ) ) ;
* /
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
{
2015-01-14 22:37:37 +00:00
var video = Global . Emulator . VideoProvider ( ) ;
2013-11-03 02:51:21 +00:00
int zoom = Global . Config . TargetZoomFactor ;
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
{
2014-05-17 03:50:19 +00:00
lastComputedSize = GlobalWin . DisplayManager . CalculateClientSize ( video , zoom ) ;
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 ( )
{
//PANTS
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 ;
}
}
2014-05-17 02:55:58 +00:00
public void ToggleFullscreen ( bool allowSuppress = false )
2013-07-14 01:48:05 +00:00
{
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 ( ) ;
2014-02-04 00:41:24 +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)
2014-02-04 21:06:00 +00:00
//At any rate, we can solve this by adding a 1px black border around the GL control
2014-02-04 00:41:24 +00:00
//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
2014-07-12 20:42:44 +00:00
if ( Global . Config . DispFullscreenHacks )
{
2014-12-14 01:43:46 +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
2014-07-12 20:42:44 +00:00
Padding = new Padding ( 1 ) ;
BackColor = Color . Black ;
}
2014-02-04 00:41:24 +00:00
#endif
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
#if WINDOWS
2014-07-12 20:42:44 +00:00
//do this even if DispFullscreenHacks arent enabled, to restore it in case it changed underneath us or something
2014-06-29 02:28:48 +00:00
Padding = new Padding ( 0 ) ;
2014-02-22 21:54:42 +00:00
//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 ;
2014-02-04 01:37:43 +00:00
#endif
2014-12-14 01:43:46 +00:00
_inFullscreen = false ;
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
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
}
2014-10-19 01:22:47 +00:00
private static LibsnesCore AsSNES { get { return Global . Emulator as LibsnesCore ; } }
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
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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 )
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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 )
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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 )
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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 )
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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 )
{
2014-11-29 21:06:15 +00:00
if ( ! ( Global . 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 ;
2013-11-27 23:35:32 +00:00
private ISoundProvider _aviSoundInput ;
2013-12-20 22:05:56 +00:00
private MetaspuSoundProvider _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 ;
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 ;
2013-11-27 23:35:32 +00:00
private int _runloopFps ;
private int _runloopLastFps ;
private bool _runloopFrameadvance ;
2015-01-31 22:16:02 +00:00
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
2013-11-27 23:35:32 +00:00
private bool _inFullscreen ;
2013-12-29 23:35:42 +00:00
private Point _windowedLocation ;
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 static string DisplayNameForSystem ( string system )
{
var str = Global . SystemInfo . DisplayName ;
if ( VersionInfo . DeveloperBuild )
{
str + = " (interim)" ;
}
return str ;
}
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 ;
2014-09-14 00:51:30 +00:00
str = str + string . Format ( "({0}x{1}) - " , size . Width , size . Height ) ;
2014-07-21 20:34:53 +00:00
}
2014-11-30 14:18:44 +00:00
if ( Global . 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
2013-12-20 22:05:56 +00:00
if ( Global . Emulator = = null )
{
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
2013-10-20 18:02:43 +00:00
if ( ! string . IsNullOrEmpty ( Global . Emulator . CoreComm . RomStatusAnnotation ) )
2013-12-20 22:05:56 +00:00
{
2013-10-20 18:02:43 +00:00
annotation = Global . 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
}
2013-11-27 23:35:32 +00:00
private static void LoadSaveRam ( )
2011-02-20 08:40:22 +00:00
{
2014-11-30 15:22:08 +00:00
if ( Global . 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
if ( Global . Emulator is GBA | | Global . Emulator is VBANext )
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
{
2014-12-05 00:34:57 +00:00
var oldram = Global . 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
}
2014-12-05 00:34:57 +00:00
Global . 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
}
2011-08-09 00:51:46 +00:00
private static void SaveRam ( )
{
2014-11-30 15:22:08 +00:00
if ( Global . 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 ) ) ;
2014-12-05 00:34:57 +00:00
var saveram = Global . 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 SelectSlot ( int num )
2011-07-09 22:09:39 +00:00
{
2014-11-30 19:48:10 +00:00
if ( Global . Emulator . HasSavestates ( ) )
{
Global . Config . SaveSlot = num ;
SaveSlotSelectedMessage ( ) ;
UpdateStatusSlots ( ) ;
}
2011-07-09 22:09:39 +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.
2013-11-27 23:35:32 +00:00
GlobalWin . Sound . SetAsyncInputPin ( _dumpProxy ) ;
2013-11-03 02:51:21 +00:00
}
2015-01-31 06:40:14 +00:00
else
2013-11-03 02:51:21 +00:00
{
Global . Emulator . EndAsyncSound ( ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . Sound . SetSyncInputPin ( Global . Emulator . SyncSoundProvider ) ;
2013-11-03 02:51:21 +00:00
}
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.
2014-10-19 01:22:47 +00:00
system = Global . Emulator . SystemId ;
//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 ;
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
if ( Global . Emulator is LibsnesCore )
{
if ( ( Global . Emulator as LibsnesCore ) . IsSGB )
{
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 ;
2014-10-19 01:22:47 +00:00
}
}
2013-10-09 20:43:13 +00:00
2013-11-27 23:35:32 +00:00
private static 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 ;
2015-02-22 18:02:56 +00:00
Global . AutofireNullControls = new AutofireController ( NullEmulator . NullController , Global . 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 )
{
2014-08-02 15:32:48 +00:00
if ( ! LoadRom ( rom ) )
2011-02-20 08:40:22 +00:00
{
2014-07-28 01:51:11 +00:00
Global . Config . RecentRoms . HandleLoadError ( 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
2013-11-27 23:35:32 +00:00
_throttle . SetCoreFps ( Global . 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 ;
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
2014-06-02 20:16:59 +00:00
private static unsafe BitmapBuffer MakeScreenshotImage ( )
2011-06-11 12:54:26 +00:00
{
2015-01-14 22:37:37 +00:00
var bb = new BitmapBuffer ( Global . Emulator . VideoProvider ( ) . BufferWidth , Global . Emulator . VideoProvider ( ) . BufferHeight , Global . Emulator . VideoProvider ( ) . GetVideoBuffer ( ) ) ;
2014-12-18 07:38:56 +00:00
bb . DiscardAlpha ( ) ;
return bb ;
2011-06-11 12:54:26 +00:00
}
2011-05-22 19:52:49 +00:00
2013-11-03 02:51:21 +00:00
private void SaveStateAs ( )
2011-05-16 15:38:48 +00:00
{
2014-11-30 18:03:02 +00:00
if ( ! Global . Emulator . HasSavestates ( ) )
2013-08-04 16:47:54 +00:00
{
return ;
}
2013-11-27 23:35:32 +00:00
var path = PathManager . GetSaveStatePath ( Global . Game ) ;
2014-11-30 14:21:11 +00:00
2013-11-03 02:51:21 +00:00
var file = new FileInfo ( path ) ;
if ( file . Directory ! = null & & file . Directory . Exists = = false )
2013-11-27 23:35:32 +00:00
{
2013-11-03 02:51:21 +00:00
file . Directory . Create ( ) ;
2013-11-27 23:35:32 +00:00
}
2013-11-03 02:51:21 +00:00
2014-11-30 14:21:11 +00:00
var sfd = new SaveFileDialog
{
AddExtension = true ,
DefaultExt = "State" ,
Filter = "Save States (*.State)|*.State|All Files|*.*" ,
InitialDirectory = path ,
FileName = PathManager . SaveStatePrefix ( Global . Game ) + "." + "QuickSave0.State"
} ;
2013-11-28 22:39:00 +00:00
var result = sfd . ShowHawkDialog ( ) ;
2013-11-27 23:35:32 +00:00
if ( result = = DialogResult . OK )
{
2013-12-30 16:49:13 +00:00
SaveState ( sfd . FileName , sfd . FileName , false ) ;
2013-11-27 23:35:32 +00:00
}
2011-02-20 08:40:22 +00:00
}
2011-06-11 12:54:26 +00:00
private void LoadStateAs ( )
{
2014-11-30 18:03:02 +00:00
if ( ! Global . Emulator . HasSavestates ( ) )
2013-11-03 02:51:21 +00:00
{
return ;
}
2013-04-16 00:19:31 +00:00
var ofd = new OpenFileDialog
2013-11-03 02:51:21 +00:00
{
InitialDirectory = PathManager . GetSaveStatePath ( Global . Game ) ,
Filter = "Save States (*.State)|*.State|All Files|*.*" ,
RestoreDirectory = true
} ;
2011-04-11 00:22:17 +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-12-20 22:05:56 +00:00
{
2011-06-11 12:54:26 +00:00
return ;
2013-12-20 22:05:56 +00:00
}
2011-04-11 00:22:17 +00:00
2011-06-11 12:54:26 +00:00
if ( File . Exists ( ofd . FileName ) = = false )
2013-11-27 23:35:32 +00:00
{
2011-06-11 12:54:26 +00:00
return ;
2013-11-27 23:35:32 +00:00
}
2011-06-11 12:54:26 +00:00
2013-12-30 16:49:13 +00:00
LoadState ( ofd . FileName , Path . GetFileName ( ofd . FileName ) ) ;
2011-06-11 12:54:26 +00:00
}
2011-04-11 00:22:17 +00:00
2013-11-27 23:35:32 +00:00
private static void SaveSlotSelectedMessage ( )
2011-02-20 08:40:22 +00:00
{
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "Slot " + Global . Config . SaveSlot + " selected." ) ;
2011-02-20 08:40:22 +00:00
}
private void Render ( )
{
2014-05-18 02:11:17 +00:00
//private Size _lastVideoSize = new Size(-1, -1), _lastVirtualSize = new Size(-1, -1);
2015-01-14 22:37:37 +00:00
var video = Global . Emulator . VideoProvider ( ) ;
2014-05-19 12:57:02 +00:00
//bool change = false;
2014-05-18 02:11:17 +00:00
Size currVideoSize = new Size ( video . BufferWidth , video . BufferHeight ) ;
Size currVirtualSize = new Size ( video . VirtualWidth , video . VirtualWidth ) ;
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
}
2013-11-27 23:35:32 +00:00
private 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 (
"Rom Files" , "*.nes;*.fds;*.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;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;%ARCH%" ,
"Music Files" , "*.psf;*.sid;*.nsf" ,
"Disc Images" , "*.cue;*.ccd;*.m3u" ,
"NES" , "*.nes;*.fds;*.nsf;%ARCH%" ,
"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%" ,
"PSX Executables (experimental)" , "*.exe" ,
"PSF Playstation Sound File (not supported)" , "*.psf" ,
"Commodore 64 (experimental)" , "*.prg; *.d64, *.g64; *.crt;%ARCH%" ,
"SID Commodore 64 Music File" , "*.sid;%ARCH%" ,
"Nintendo 64" , "*.z64;*.v64;*.n64" ,
"WonderSwan" , "*.ws;*.wsc;%ARCH%" ,
"Apple II" , "*.dsk;%ARCH%" ,
"All Files" , "*.*" ) ;
}
return FormatFilter (
2014-12-04 05:40:10 +00:00
"Rom Files" , "*.nes;*.fds;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.rom;*.cue;*.ccd;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;%ARCH%" ,
2014-12-14 10:36:03 +00:00
"Disc Images" , "*.cue;*.ccd;*.m3u" ,
2015-03-11 09:46:27 +00:00
"NES" , "*.nes;*.fds;*.nsf;%ARCH%" ,
2013-04-24 22:09:11 +00:00
"Super NES" , "*.smc;*.sfc;*.xml;%ARCH%" ,
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%" ,
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
{
InitialDirectory = PathManager . GetRomsPath ( Global . Emulator . SystemId ) ,
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 ;
2014-08-02 15:32:48 +00:00
LoadRom ( file . FullName ) ;
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
{
MessageBox . Show (
"No sync settings found, using currently configured settings for this core." ,
"No sync settings found" ,
MessageBoxButtons . OK ,
MessageBoxIcon . Warning
) ;
e . Settings = Global . Config . GetCoreSyncSettings ( e . Core ) ;
}
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
{
2014-12-17 01:23:24 +00:00
var settable = new SettingsAdapter ( Global . Emulator ) ;
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
{
2014-10-31 15:46:13 +00:00
var settable = new SettingsAdapter ( Global . 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
}
2014-10-31 15:46:13 +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
}
}
2013-11-03 02:51:21 +00:00
private void SaveConfig ( )
{
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 ( ) ;
}
2013-11-03 02:51:21 +00:00
ConfigService . Save ( PathManager . DefaultIniPath , Global . Config ) ;
}
private void PreviousSlot ( )
{
2014-11-30 19:48:10 +00:00
if ( Global . Emulator . HasSavestates ( ) )
2013-11-27 23:35:32 +00:00
{
2014-11-30 19:48:10 +00:00
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 - - ;
}
2013-12-20 22:05:56 +00:00
2014-11-30 19:48:10 +00:00
SaveSlotSelectedMessage ( ) ;
UpdateStatusSlots ( ) ;
}
2013-11-03 02:51:21 +00:00
}
private void NextSlot ( )
{
2014-11-30 19:48:10 +00:00
if ( Global . Emulator . HasSavestates ( ) )
2013-11-27 23:35:32 +00:00
{
2014-11-30 19:48:10 +00:00
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 + + ;
}
2013-11-27 23:35:32 +00:00
2014-11-30 19:48:10 +00:00
SaveSlotSelectedMessage ( ) ;
UpdateStatusSlots ( ) ;
}
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
2015-01-25 03:33:45 +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
2015-01-25 03:33:45 +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
2014-01-16 16:32:34 +00:00
private static 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..
2013-11-03 02:51:21 +00:00
if ( Global . 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
2014-01-16 16:32:34 +00:00
private static 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..
2013-11-03 02:51:21 +00:00
if ( Global . 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 =
Global . 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
{
2015-01-14 22:37:37 +00:00
var bb = GlobalWin . DisplayManager . RenderOffscreen ( Global . Emulator . VideoProvider ( ) , true ) ;
2014-06-02 20:16:59 +00:00
bb . Normalize ( true ) ;
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
{
2013-11-03 02:51:21 +00:00
switch ( Global . Config . TargetZoomFactor )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
case 1 :
Global . Config . TargetZoomFactor = 2 ;
break ;
case 2 :
Global . Config . TargetZoomFactor = 3 ;
break ;
case 3 :
Global . Config . TargetZoomFactor = 4 ;
break ;
case 4 :
Global . Config . TargetZoomFactor = 5 ;
break ;
case 5 :
Global . Config . TargetZoomFactor = 10 ;
break ;
case 10 :
return ;
2011-06-11 12:54:26 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-26 23:47:59 +00:00
GlobalWin . OSD . AddMessage ( "Screensize set to " + Global . Config . TargetZoomFactor + "x" ) ;
2013-11-03 02:51:21 +00:00
FrameBufferResized ( ) ;
}
private void DecreaseWIndowSize ( )
{
switch ( Global . Config . TargetZoomFactor )
2011-06-11 12:54:26 +00:00
{
2013-11-03 02:51:21 +00:00
case 1 :
return ;
case 2 :
Global . Config . TargetZoomFactor = 1 ;
break ;
case 3 :
Global . Config . TargetZoomFactor = 2 ;
break ;
case 4 :
Global . Config . TargetZoomFactor = 3 ;
break ;
case 5 :
Global . Config . TargetZoomFactor = 4 ;
break ;
case 10 :
Global . Config . TargetZoomFactor = 5 ;
return ;
2011-06-11 12:54:26 +00:00
}
2013-12-20 22:05:56 +00:00
2014-10-26 23:47:59 +00:00
GlobalWin . OSD . AddMessage ( "Screensize set to " + Global . Config . TargetZoomFactor + "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 )
{
2014-12-12 01:49:54 +00:00
var hasDriveLight = Global . Emulator . HasDriveLight ( ) & & Global . Emulator . AsDriveLight ( ) . DriveLightEnabled ;
if ( hasDriveLight )
2013-11-03 02:51:21 +00:00
{
if ( ! LedLightStatusLabel . Visible )
{
LedLightStatusLabel . Visible = true ;
}
2013-12-20 22:05:56 +00:00
2014-12-12 01:49:54 +00:00
LedLightStatusLabel . Image = Global . 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
if ( Global . Emulator . CoreComm . UsesLinkCable )
{
if ( ! LinkConnectStatusBarButton . Visible )
{
LinkConnectStatusBarButton . Visible = true ;
}
LinkConnectStatusBarButton . Image = Global . Emulator . CoreComm . LinkConnected
? 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 (
2013-12-20 22:05:56 +00:00
"Display Vsync set to " + ( Global . Config . VSyncThrottle ? "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
{
if ( Global . Emulator . ControllerDefinition . BoolButtons . Contains ( button ) )
{
if ( ! Global . MovieSession . Movie . IsPlaying | | Global . MovieSession . Movie . IsFinished )
{
Global . ClickyVirtualPadController . Click ( button ) ;
GlobalWin . OSD . AddMessage ( msg ) ;
}
}
} ) ;
}
2013-12-30 16:49:13 +00:00
public void LoadState ( string path , string userFriendlyStateName , bool fromLua = false ) // Move to client.common
{
2014-11-30 17:51:16 +00:00
if ( ! Global . Emulator . HasSavestates ( ) )
{
return ;
}
2014-10-20 20:31:31 +00:00
// If from lua, disable counting rerecords
bool wasCountingRerecords = Global . MovieSession . Movie . IsCountingRerecords ;
if ( fromLua )
Global . MovieSession . Movie . IsCountingRerecords = false ;
2013-12-30 16:49:13 +00:00
GlobalWin . DisplayManager . NeedsToPaint = true ;
if ( SavestateManager . LoadStateFile ( path , userFriendlyStateName ) )
{
SetMainformMovieInfo ( ) ;
GlobalWin . OSD . ClearGUIText ( ) ;
GlobalWin . Tools . UpdateToolsBefore ( fromLua ) ;
UpdateToolsAfter ( fromLua ) ;
UpdateToolsLoadstate ( ) ;
2014-08-16 14:33:09 +00:00
Global . AutoFireController . ClearStarts ( ) ;
2013-12-30 16:49:13 +00:00
GlobalWin . OSD . AddMessage ( "Loaded state: " + userFriendlyStateName ) ;
if ( GlobalWin . Tools . Has < LuaConsole > ( ) )
{
GlobalWin . Tools . LuaConsole . LuaImp . CallLoadStateEvent ( userFriendlyStateName ) ;
}
}
else
{
GlobalWin . OSD . AddMessage ( "Loadstate error!" ) ;
}
2014-10-20 20:31:31 +00:00
Global . MovieSession . Movie . IsCountingRerecords = wasCountingRerecords ;
2013-12-30 16:49:13 +00:00
}
public void LoadQuickSave ( string quickSlotName , bool fromLua = false )
{
2014-11-30 17:51:16 +00:00
if ( ! Global . Emulator . HasSavestates ( ) )
2013-12-30 16:49:13 +00:00
{
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 ) ;
}
public void SaveState ( string path , string userFriendlyStateName , bool fromLua )
{
2014-11-30 17:51:16 +00:00
if ( ! Global . Emulator . HasSavestates ( ) )
{
return ;
}
2014-08-18 18:06:15 +00:00
try
{
SavestateManager . SaveStateFile ( path , userFriendlyStateName ) ;
2013-12-30 16:49:13 +00:00
2014-08-18 18:06:15 +00:00
GlobalWin . OSD . AddMessage ( "Saved state: " + userFriendlyStateName ) ;
}
catch ( IOException )
{
GlobalWin . OSD . AddMessage ( "Unable to save state " + path ) ;
}
2013-12-30 16:49:13 +00:00
if ( ! fromLua )
{
UpdateStatusSlots ( ) ;
}
}
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
{
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 ( )
{
2014-11-30 14:18:44 +00:00
if ( Global . Emulator . IsNull ( ) )
2014-04-25 01:19:57 +00:00
{
CoreNameStatusBarButton . Visible = false ;
return ;
}
CoreNameStatusBarButton . Visible = true ;
2014-07-29 01:11:57 +00:00
var attributes = Global . Emulator . Attributes ( ) ;
2014-04-25 01:19:57 +00:00
2014-07-29 01:11:57 +00:00
CoreNameStatusBarButton . Text = Global . Emulator . DisplayName ( ) ;
CoreNameStatusBarButton . Image = Global . 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
{
if ( Global . Emulator . CanPollInput ( ) )
{
2014-12-05 00:59:00 +00:00
return Global . 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
2014-11-30 20:29:30 +00:00
if ( Global . Config . SkipLagFrame & & IsLagFrame & & frameProgressTimeElapsed & & Global . 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
}
2013-11-03 16:47:21 +00:00
if ( Global . ClientControls [ "Frame Advance" ] | | PressFrameAdvance )
2012-10-07 19:52:09 +00:00
{
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 ;
2013-11-27 23:35:32 +00:00
_runloopFrameadvance = 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 ) ;
2013-12-27 00:47:52 +00:00
2013-11-03 02:51:21 +00:00
if ( UpdateFrame )
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
}
2013-12-29 23:35:42 +00:00
var genSound = false ;
var coreskipaudio = false ;
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 ( ) ;
}
2014-07-27 17:49:25 +00:00
if ( ! IsTurboing )
2013-11-03 02:51:21 +00:00
{
2013-11-27 23:35:32 +00:00
GlobalWin . Tools . UpdateToolsBefore ( ) ;
2013-11-03 02:51:21 +00:00
}
2014-07-25 01:55:21 +00:00
else
{
GlobalWin . Tools . FastUpdateBefore ( ) ;
}
2013-11-03 02:51:21 +00:00
2013-11-27 23:35:32 +00:00
_runloopFps + + ;
2013-11-03 02:51:21 +00:00
2015-01-31 22:16:02 +00:00
if ( ( double ) ( currentTimestamp - _runloopSecond ) / Stopwatch . Frequency > = 1.0 )
2013-11-03 02:51:21 +00:00
{
2013-11-27 23:35:32 +00:00
_runloopLastFps = _runloopFps ;
2015-01-31 22:16:02 +00:00
_runloopSecond = currentTimestamp ;
2013-11-27 23:35:32 +00:00
_runloopFps = 0 ;
2013-11-03 02:51:21 +00:00
updateFpsString = true ;
}
if ( updateFpsString )
{
2013-12-29 23:35:42 +00:00
var fps_string = _runloopLastFps + " fps" ;
2014-07-11 17:14:45 +00:00
if ( isRewinding )
{
2014-07-27 17:49:25 +00:00
if ( IsTurboing | | isFastForwarding )
2014-07-11 17:14:45 +00:00
{
fps_string + = " <<<<" ;
}
else
{
fps_string + = " <<" ;
}
}
2014-07-27 17:49:25 +00:00
else if ( IsTurboing )
2013-11-03 02:51:21 +00:00
{
fps_string + = " >>>>" ;
}
2013-12-29 23:35:42 +00:00
else if ( isFastForwarding )
2013-11-03 02:51:21 +00:00
{
fps_string + = " >>" ;
}
2013-12-29 23:35:42 +00:00
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . FPS = fps_string ;
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
2013-12-29 23:35:42 +00:00
if ( ! _runloopFrameadvance )
{
genSound = true ;
}
2013-11-03 02:51:21 +00:00
else if ( ! Global . Config . MuteFrameAdvance )
2013-12-29 23:35:42 +00:00
{
2013-11-03 02:51:21 +00:00
genSound = true ;
2013-12-29 23:35:42 +00:00
}
2013-11-03 02:51:21 +00:00
2013-11-03 16:53:05 +00:00
Global . MovieSession . HandleMovieOnFrameLoop ( ) ;
2013-11-03 02:51:21 +00:00
2014-07-27 17:49:25 +00:00
coreskipaudio = IsTurboing & & _currAviWriter = = null ;
2013-12-29 23:35:42 +00:00
2014-06-08 23:30:34 +00:00
{
bool render = ! _throttle . skipnextframe | | _currAviWriter ! = null ;
bool renderSound = ! coreskipaudio ;
Global . Emulator . FrameAdvance ( render , renderSound ) ;
}
2015-03-16 20:42:14 +00:00
Global . MovieSession . HandleMovieAfterFrameLoop ( ) ;
2013-11-03 16:07:58 +00:00
GlobalWin . DisplayManager . NeedsToPaint = true ;
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 ( ) ;
}
2014-07-27 17:49:25 +00:00
if ( ! IsTurboing )
2013-11-03 02:51:21 +00:00
{
UpdateToolsAfter ( ) ;
}
2014-07-25 01:55:21 +00:00
else
{
GlobalWin . Tools . FastUpdateAfter ( ) ;
}
2014-07-26 13:06:19 +00:00
2014-07-27 19:07:13 +00:00
if ( IsSeeking & & Global . Emulator . Frame = = PauseOnFrame . Value )
2014-07-26 13:06:19 +00:00
{
PauseEmulator ( ) ;
PauseOnFrame = null ;
}
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 ( ) ;
PressRewind = false ;
2012-10-07 19:52:09 +00:00
}
2013-12-29 23:35:42 +00:00
2013-11-03 02:51:21 +00:00
if ( UpdateFrame )
2012-10-07 19:52:09 +00:00
{
2013-11-03 02:51:21 +00:00
UpdateFrame = false ;
2012-10-07 19:52:09 +00:00
}
2015-01-31 04:49:53 +00:00
bool outputSilence = ! genSound | | coreskipaudio ;
GlobalWin . Sound . UpdateSound ( outputSilence ) ;
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 ;
if ( unattended )
{
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
{
2014-10-11 03:33:09 +00:00
if ( _dumpaudiosync )
{
aw = new VideoStretcher ( aw ) ;
}
else
{
aw = new AudioStretcher ( aw ) ;
}
2013-10-20 18:02:43 +00:00
aw . SetMovieParameters ( Global . Emulator . CoreComm . VsyncNum , Global . 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
{
2015-01-14 22:37:37 +00:00
aw . SetVideoParameters ( Global . Emulator . VideoProvider ( ) . BufferWidth , Global . Emulator . VideoProvider ( ) . 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
2012-07-23 00:33:30 +00:00
if ( unattended )
2012-05-28 01:29:43 +00:00
{
2012-07-23 00:33:30 +00:00
aw . SetDefaultVideoCodecToken ( ) ;
}
else
{
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
2012-07-23 00:33:30 +00:00
if ( unattended )
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 )
{
Global . Emulator . EndAsyncSound ( ) ;
}
else
{
_aviSoundInput = ! Global . Emulator . StartAsyncSound ( )
? new MetaspuAsync ( Global . Emulator . SyncSoundProvider , ESynchMethod . ESynchMethod_V )
: Global . Emulator . SoundProvider ;
}
2013-11-27 23:35:32 +00:00
_dumpProxy = new MetaspuSoundProvider ( ESynchMethod . ESynchMethod_V ) ;
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 ;
2013-11-27 23:35:32 +00:00
_aviSoundInput = null ;
_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 ;
2013-11-27 23:35:32 +00:00
_aviSoundInput = null ;
_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-23 00:51:31 +00:00
GlobalWin . DisplayManager . NeedsToPaint = true ;
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 )
{
if ( ! _currAviWriterFrameList . Contains ( Global . Emulator . Frame ) )
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
{
2015-01-14 22:37:37 +00:00
bbin = new BitmapBuffer ( Global . Emulator . VideoProvider ( ) . BufferWidth , Global . Emulator . VideoProvider ( ) . BufferHeight , Global . Emulator . VideoProvider ( ) . GetVideoBuffer ( ) ) ;
2014-02-07 02:28:07 +00:00
}
2013-12-29 23:35:42 +00:00
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 )
{
2015-01-14 22:37:37 +00:00
g . Clear ( Color . FromArgb ( Global . Emulator . VideoProvider ( ) . 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
2015-01-14 22:37:37 +00:00
output = Global . Emulator . VideoProvider ( ) ;
2012-11-26 21:08:08 +00:00
}
2014-06-18 02:28:07 +00:00
_currAviWriter . SetFrame ( Global . Emulator . Frame ) ;
2014-10-11 03:33:09 +00:00
short [ ] samp ;
int nsamp ;
if ( _dumpaudiosync )
{
( _currAviWriter as VideoStretcher ) . DumpAV ( output , Global . Emulator . SyncSoundProvider , out samp , out nsamp ) ;
}
else
{
( _currAviWriter as AudioStretcher ) . DumpAV ( output , _aviSoundInput , out samp , out nsamp ) ;
}
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
2014-10-11 03:33:09 +00:00
_dumpProxy . buffer . enqueue_samples ( 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
}
}
}
2013-12-29 23:35:42 +00:00
2013-11-23 00:51:31 +00:00
GlobalWin . DisplayManager . NeedsToPaint = 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 )
{
FirmwaresMenuItem_Click ( null , null ) ;
}
}
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 ;
}
2013-12-25 19:09:53 +00:00
// Still needs a good bit of refactoring
2014-05-24 22:06:08 +00:00
public bool LoadRom ( string path , bool? deterministicemulation = null )
2013-12-25 19:09:53 +00:00
{
2014-08-19 19:24:17 +00:00
// If deterministic emulation is passed in, respect that value regardless, else determine a good value (currently that simply means movies require deterministic emulaton)
2014-05-24 22:06:08 +00:00
bool deterministic = deterministicemulation . HasValue ?
deterministicemulation . Value :
2014-08-27 05:52:35 +00:00
Global . MovieSession . QueuedMovie ! = null ;
//Global.MovieSession.Movie.IsActive;
2014-05-24 22:06:08 +00:00
2014-01-01 19:07:23 +00:00
if ( ! GlobalWin . Tools . AskSave ( ) )
{
return false ;
}
2014-01-01 03:03:10 +00:00
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 ,
MessageCallback = GlobalWin . OSD . AddMessage
2013-12-26 01:00:44 +00:00
} ;
2015-02-05 23:53:25 +00:00
Global . FirmwareManager . RecentlyServed . Clear ( ) ;
2013-12-26 01:00:44 +00:00
2013-12-25 19:09:53 +00:00
loader . OnLoadError + = ShowLoadError ;
2013-12-26 20:19:28 +00:00
loader . OnLoadSettings + = CoreSettings ;
loader . OnLoadSyncSettings + = CoreSyncSettings ;
2014-01-01 21:24:58 +00:00
// 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
2014-06-21 21:39:18 +00:00
CommitCoreSettingsToConfig ( ) ; // adelikat: I Think by reordering things, this isn't necessary anymore
CloseGame ( ) ;
2014-10-19 01:22:47 +00:00
2014-06-08 23:30:34 +00:00
var nextComm = CreateCoreComm ( ) ;
2014-01-01 21:24:58 +00:00
CoreFileProvider . SyncCoreCommInputSignals ( nextComm ) ;
var result = loader . LoadRom ( path , nextComm ) ;
2013-11-03 02:51:21 +00:00
2013-12-25 19:09:53 +00:00
if ( result )
{
2013-12-26 01:00:44 +00:00
Global . Emulator = loader . LoadedEmulator ;
Global . Game = loader . Game ;
2015-02-22 20:06:30 +00:00
CoreFileProvider . SyncCoreCommInputSignals ( nextComm ) ;
2013-12-24 21:59:41 +00:00
InputManager . SyncControls ( ) ;
2012-07-12 23:13:22 +00:00
2015-02-07 14:30:14 +00:00
if ( Global . Emulator is TI83 & & Global . Config . TI83autoloadKeyPad )
{
GlobalWin . Tools . Load < TI83KeyPad > ( ) ;
}
2013-12-29 23:35:42 +00:00
if ( loader . LoadedEmulator is NES )
2013-11-03 02:51:21 +00:00
{
2013-12-29 23:35:42 +00:00
var nes = loader . LoadedEmulator as NES ;
2014-05-23 15:10:14 +00:00
if ( ! string . IsNullOrWhiteSpace ( nes . GameName ) )
2013-12-20 22:05:56 +00:00
{
2013-11-03 02:51:21 +00:00
Global . Game . Name = nes . GameName ;
2013-12-20 22:05:56 +00:00
}
2013-11-03 02:51:21 +00:00
Global . Game . Status = nes . RomStatus ;
}
2014-07-23 02:48:55 +00:00
else if ( loader . LoadedEmulator is QuickNES )
{
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 ;
}
}
2012-09-29 23:03:51 +00:00
2013-12-27 01:19:38 +00:00
Global . Rewinder . ResetRewindBuffer ( ) ;
2012-09-30 00:53:08 +00:00
2013-12-26 01:00:44 +00:00
if ( Global . Emulator . CoreComm . RomStatusDetails = = null & & loader . Rom ! = null )
2013-11-03 02:51:21 +00:00
{
2013-12-29 23:35:42 +00:00
Global . Emulator . CoreComm . RomStatusDetails = string . Format (
"{0}\r\nSHA1:{1}\r\nMD5:{2}\r\n" ,
2013-12-26 01:00:44 +00:00
loader . Game . Name ,
2014-07-03 19:20:34 +00:00
loader . Rom . RomData . HashSHA1 ( ) ,
loader . Rom . RomData . HashMD5 ( ) ) ;
2013-11-03 02:51:21 +00:00
}
2012-10-28 23:38:41 +00:00
2013-11-03 02:51:21 +00:00
if ( Global . Emulator . BoardName ! = null )
2012-11-26 01:28:14 +00:00
{
2013-11-03 02:51:21 +00:00
Console . WriteLine ( "Core reported BoardID: \"{0}\"" , Global . Emulator . BoardName ) ;
2012-11-26 01:28:14 +00:00
}
2013-11-03 02:51:21 +00:00
2013-12-20 22:05:56 +00:00
// restarts the lua console if a different rom is loaded.
// im not really a fan of how this is done..
2014-04-06 20:46:23 +00:00
if ( Global . Config . RecentRoms . Empty | | Global . Config . RecentRoms . MostRecent ! = loader . CanonicalFullPath )
2012-11-26 01:28:14 +00:00
{
2013-11-03 16:07:58 +00:00
GlobalWin . Tools . Restart < LuaConsole > ( ) ;
2012-11-26 01:28:14 +00:00
}
2012-11-26 23:16:31 +00:00
2013-12-26 01:00:44 +00:00
Global . Config . RecentRoms . Add ( loader . CanonicalFullPath ) ;
JumpLists . AddRecentItem ( loader . CanonicalFullPath ) ;
2014-08-02 15:32:48 +00:00
// Don't load Save Ram if a movie is being loaded
if ( ! Global . MovieSession . MovieIsQueued & & File . Exists ( PathManager . SaveRamPath ( loader . Game ) ) )
2013-11-03 02:51:21 +00:00
{
LoadSaveRam ( ) ;
}
2013-12-20 22:05:56 +00:00
2013-11-03 16:07:58 +00:00
GlobalWin . Tools . Restart ( ) ;
2013-03-10 23:03:52 +00:00
2013-11-03 02:51:21 +00:00
if ( Global . Config . LoadCheatFileByGame )
{
if ( Global . CheatList . AttemptToLoadCheatFile ( ) )
{
2013-11-03 16:07:58 +00:00
GlobalWin . OSD . AddMessage ( "Cheats file loaded" ) ;
2013-11-03 02:51:21 +00:00
}
}
2013-07-27 01:03:15 +00:00
2014-08-02 15:32:48 +00:00
SetWindowText ( ) ;
2013-12-26 01:00:44 +00:00
CurrentlyOpenRom = loader . CanonicalFullPath ;
2013-11-03 02:51:21 +00:00
HandlePlatformMenus ( ) ;
2013-11-27 23:35:32 +00:00
_stateSlots . Clear ( ) ;
2014-04-25 01:19:57 +00:00
UpdateCoreStatusBarButton ( ) ;
2013-11-03 02:51:21 +00:00
UpdateDumpIcon ( ) ;
2014-07-17 02:00:17 +00:00
SetMainformMovieInfo ( ) ;
2013-10-11 16:32:36 +00:00
2013-12-27 01:19:38 +00:00
Global . Rewinder . CaptureRewindState ( ) ;
2013-10-27 07:54:00 +00:00
2013-11-03 02:51:21 +00:00
Global . StickyXORAdapter . ClearStickies ( ) ;
Global . StickyXORAdapter . ClearStickyFloats ( ) ;
2013-11-03 16:47:21 +00:00
Global . AutofireStickyXORAdapter . ClearStickies ( ) ;
2013-10-27 07:54:00 +00:00
2013-11-03 02:51:21 +00:00
RewireSound ( ) ;
2013-12-21 16:42:36 +00:00
ToolHelpers . UpdateCheatRelatedTools ( null , null ) ;
2014-07-21 22:38:53 +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-02-05 23:53:25 +00:00
if ( Global . FirmwareManager . RecentlyServed . Count > 0 )
2015-02-05 23:25:28 +00:00
{
Console . WriteLine ( "Active Firmwares:" ) ;
2015-02-05 23:53:25 +00:00
foreach ( var f in Global . FirmwareManager . RecentlyServed )
2015-02-05 23:25:28 +00:00
{
2015-02-05 23:53:25 +00:00
Console . WriteLine ( " {0} : {1}" , f . FirmwareId , f . Hash ) ;
2015-02-05 23:25:28 +00:00
}
2014-07-21 22:38:53 +00:00
}
2013-11-03 02:51:21 +00:00
return true ;
2013-10-27 07:54:00 +00:00
}
2013-12-25 19:09:53 +00:00
else
{
2014-10-19 01:22:47 +00:00
//This shows up if there's a problem
2014-08-01 01:45:19 +00:00
// TODO: put all these in a single method or something
HandlePlatformMenus ( ) ;
_stateSlots . Clear ( ) ;
UpdateStatusSlots ( ) ;
2014-07-31 20:42:12 +00:00
UpdateCoreStatusBarButton ( ) ;
2014-08-01 01:45:19 +00:00
UpdateDumpIcon ( ) ;
SetMainformMovieInfo ( ) ;
SetWindowText ( ) ;
2013-12-25 19:09:53 +00:00
return false ;
}
}
2013-12-30 16:49:13 +00:00
// TODO: should backup logic be stuffed in into Client.Common.SaveStateManager?
public void SaveQuickSave ( string quickSlotName )
2013-10-27 07:54:00 +00:00
{
2014-11-30 17:51:16 +00:00
if ( ! Global . Emulator . HasSavestates ( ) )
2013-10-27 07:54:00 +00:00
{
2013-11-03 02:51:21 +00:00
return ;
2013-10-27 07:54:00 +00:00
}
2013-12-30 16:49:13 +00:00
var path = PathManager . SaveStatePrefix ( Global . Game ) + "." + quickSlotName + ".State" ;
2013-10-27 15:23:41 +00:00
2013-11-03 02:51:21 +00:00
var file = new FileInfo ( path ) ;
if ( file . Directory ! = null & & file . Directory . Exists = = false )
2013-11-27 23:35:32 +00:00
{
2013-11-03 02:51:21 +00:00
file . Directory . Create ( ) ;
2013-11-27 23:35:32 +00:00
}
2013-10-27 15:23:41 +00:00
2014-01-01 03:03:10 +00:00
2013-12-20 22:05:56 +00:00
// Make backup first
2013-11-03 02:51:21 +00:00
if ( Global . Config . BackupSavestates & & file . Exists )
2013-10-27 15:23:41 +00:00
{
2013-11-27 23:35:32 +00:00
var backup = path + ".bak" ;
2013-11-03 02:51:21 +00:00
var backupFile = new FileInfo ( backup ) ;
if ( backupFile . Exists )
2013-11-27 23:35:32 +00:00
{
2013-11-03 02:51:21 +00:00
backupFile . Delete ( ) ;
2013-11-27 23:35:32 +00:00
}
2013-12-29 23:35:42 +00:00
2014-10-09 22:04:56 +00:00
File . Move ( path , backup ) ;
2013-10-27 15:23:41 +00:00
}
2013-12-30 16:49:13 +00:00
SaveState ( path , quickSlotName , false ) ;
2013-11-03 02:51:21 +00:00
2013-11-03 16:07:58 +00:00
if ( GlobalWin . Tools . Has < LuaConsole > ( ) )
2013-10-27 15:23:41 +00:00
{
2013-12-30 16:49:13 +00:00
GlobalWin . Tools . LuaConsole . LuaImp . CallSaveStateEvent ( quickSlotName ) ;
2013-10-27 15:23:41 +00:00
}
}
2013-12-29 23:35:42 +00:00
private static void CommitCoreSettingsToConfig ( )
2013-12-23 23:03:12 +00:00
{
// save settings object
2013-12-29 23:35:42 +00:00
var t = Global . Emulator . GetType ( ) ;
2014-10-31 15:46:13 +00:00
var settable = new SettingsAdapter ( Global . Emulator ) ;
2014-10-19 01:22:47 +00:00
2014-10-31 15:46:13 +00:00
if ( settable . HasSettings )
{
Global . Config . PutCoreSettings ( settable . GetSettings ( ) , t ) ;
}
2014-01-01 03:03:10 +00:00
2014-10-31 15:46:13 +00:00
if ( settable . HasSyncSettings & & ! Global . MovieSession . Movie . IsActive )
2013-12-29 23:35:42 +00:00
{
2014-10-31 15:46:13 +00:00
// don't trample config with loaded-from-movie settings
Global . Config . PutCoreSyncSettings ( settable . GetSyncSettings ( ) , t ) ;
2013-12-29 23:35:42 +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
}
}
2014-12-05 00:34:57 +00:00
else if ( Global . Emulator . HasSaveRam ( ) & & Global . 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
Global . CheatList . SaveOnClose ( ) ;
2013-11-03 02:51:21 +00:00
Global . Emulator . Dispose ( ) ;
2015-02-22 20:06:30 +00:00
var coreComm = CreateCoreComm ( ) ;
CoreFileProvider . SyncCoreCommInputSignals ( coreComm ) ;
Global . 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
}
2014-10-20 00:31:05 +00:00
public bool GameIsClosing { get ; set ; } // Let's tools make better decisions when being called by CloseGame
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 ) ;
Global . 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 ;
2013-12-21 19:34:01 +00:00
ToolHelpers . UpdateCheatRelatedTools ( null , null ) ;
2014-12-05 00:52:16 +00:00
UpdateStatusSlots ( ) ;
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 ; }
2014-07-08 16:08:52 +00:00
public void RelinquishControl ( IControlMainform master )
{
2014-08-19 19:24:17 +00:00
this . master = master ;
}
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-07-08 16:08:52 +00:00
private bool IsSlave
{
2014-08-19 19:24:17 +00:00
get { return master ! = null ; }
2014-07-08 16:08:52 +00:00
}
2014-08-19 19:24:17 +00:00
public void TakeBackControl ( )
2014-07-08 16:08:52 +00:00
{
2014-08-19 19:24:17 +00:00
master = null ;
2014-07-08 16:08:52 +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
{
if ( IsSlave & & master . WantsToControlRewind )
{
if ( Global . ClientControls [ "Rewind" ] | | PressRewind )
{
runFrame = false ; // TODO: the master should be deciding this!
return master . Rewind ( ) ;
}
}
var isRewinding = false ;
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
private void LinkConnectStatusBarButton_Click ( object sender , EventArgs e )
{
// TODO: it would be cool if clicking this toggled the state
2014-11-20 16:54:06 +00:00
if ( Global . Emulator . CoreComm . LinkConnected = = true )
{
//Disconnect
//This Value: cablediscosignal_new Changes to False, The Core will disconnect
}
else if ( Global . Emulator . CoreComm . LinkConnected = = false )
{
//Reconnect
}
2014-08-23 01:18:59 +00:00
}
2014-10-29 22:28:14 +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
}
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 > ( ) ;
}
2014-10-19 01:22:47 +00:00
}
2012-03-09 12:10:41 +00:00
}