2014-06-25 16:29:58 +00:00
//EmulationStation, a graphical front-end for ROM browsing. Created by Alec "Aloshi" Lofquist.
//http://www.aloshi.com
# include "guis/GuiDetectDevice.h"
# include "guis/GuiMsgBox.h"
2018-01-09 22:55:09 +00:00
# include "utils/FileSystemUtil.h"
2017-11-01 22:21:10 +00:00
# include "views/ViewController.h"
# include "CollectionSystemManager.h"
2014-06-25 16:29:58 +00:00
# include "EmulationStation.h"
2017-11-01 22:21:10 +00:00
# include "InputManager.h"
# include "Log.h"
2018-02-09 17:23:58 +00:00
# include "MameNames.h"
2017-11-01 22:21:10 +00:00
# include "platform.h"
2017-07-20 07:07:02 +00:00
# include "PowerSaver.h"
2014-06-25 16:29:58 +00:00
# include "ScraperCmdLine.h"
2017-11-01 22:21:10 +00:00
# include "Settings.h"
# include "SystemData.h"
# include "SystemScreenSaver.h"
# include <SDL_events.h>
# include <SDL_main.h>
# include <SDL_timer.h>
# include <iostream>
2018-01-29 22:50:10 +00:00
# include <time.h>
2014-11-25 02:49:11 +00:00
# ifdef WIN32
# include <Windows.h>
# endif
2017-11-01 22:21:10 +00:00
# include <FreeImage.h>
2014-06-25 16:29:58 +00:00
bool scrape_cmdline = false ;
2017-12-01 17:42:27 +00:00
bool parseArgs ( int argc , char * argv [ ] )
2014-06-25 16:29:58 +00:00
{
2018-02-08 18:27:44 +00:00
Settings : : getInstance ( ) - > setString ( " ExePath " , argv [ 0 ] ) ;
2014-06-25 16:29:58 +00:00
for ( int i = 1 ; i < argc ; i + + )
{
if ( strcmp ( argv [ i ] , " --resolution " ) = = 0 )
{
if ( i > = argc - 2 )
{
std : : cerr < < " Invalid resolution supplied. " ;
return false ;
}
2017-12-01 17:42:27 +00:00
int width = atoi ( argv [ i + 1 ] ) ;
int height = atoi ( argv [ i + 2 ] ) ;
2014-06-25 16:29:58 +00:00
i + = 2 ; // skip the argument value
2017-12-01 17:42:27 +00:00
Settings : : getInstance ( ) - > setInt ( " WindowWidth " , width ) ;
Settings : : getInstance ( ) - > setInt ( " WindowHeight " , height ) ;
} else if ( strcmp ( argv [ i ] , " --screensize " ) = = 0 )
{
if ( i > = argc - 2 )
{
std : : cerr < < " Invalid screensize supplied. " ;
return false ;
}
int width = atoi ( argv [ i + 1 ] ) ;
int height = atoi ( argv [ i + 2 ] ) ;
i + = 2 ; // skip the argument value
Settings : : getInstance ( ) - > setInt ( " ScreenWidth " , width ) ;
Settings : : getInstance ( ) - > setInt ( " ScreenHeight " , height ) ;
} else if ( strcmp ( argv [ i ] , " --screenoffset " ) = = 0 )
{
if ( i > = argc - 2 )
{
std : : cerr < < " Invalid screenoffset supplied. " ;
return false ;
}
int x = atoi ( argv [ i + 1 ] ) ;
int y = atoi ( argv [ i + 2 ] ) ;
i + = 2 ; // skip the argument value
Settings : : getInstance ( ) - > setInt ( " ScreenOffsetX " , x ) ;
Settings : : getInstance ( ) - > setInt ( " ScreenOffsetY " , y ) ;
2018-01-18 17:30:00 +00:00
} else if ( strcmp ( argv [ i ] , " --screenrotate " ) = = 0 )
{
if ( i > = argc - 1 )
{
std : : cerr < < " Invalid screenrotate supplied. " ;
return false ;
}
int rotate = atoi ( argv [ i + 1 ] ) ;
+ + i ; // skip the argument value
Settings : : getInstance ( ) - > setInt ( " ScreenRotate " , rotate ) ;
2014-06-25 16:29:58 +00:00
} else if ( strcmp ( argv [ i ] , " --gamelist-only " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " ParseGamelistOnly " , true ) ;
} else if ( strcmp ( argv [ i ] , " --ignore-gamelist " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " IgnoreGamelist " , true ) ;
2017-07-24 23:12:40 +00:00
} else if ( strcmp ( argv [ i ] , " --show-hidden-files " ) = = 0 )
{
2017-08-02 19:56:33 +00:00
Settings : : getInstance ( ) - > setBool ( " ShowHiddenFiles " , true ) ;
2014-06-25 16:29:58 +00:00
} else if ( strcmp ( argv [ i ] , " --draw-framerate " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " DrawFramerate " , true ) ;
} else if ( strcmp ( argv [ i ] , " --no-exit " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " ShowExit " , false ) ;
2017-01-12 19:17:53 +00:00
} else if ( strcmp ( argv [ i ] , " --no-splash " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " SplashScreen " , false ) ;
2014-06-25 16:29:58 +00:00
} else if ( strcmp ( argv [ i ] , " --debug " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " Debug " , true ) ;
2014-11-25 02:49:11 +00:00
Settings : : getInstance ( ) - > setBool ( " HideConsole " , false ) ;
2014-06-25 16:29:58 +00:00
Log : : setReportingLevel ( LogDebug ) ;
} else if ( strcmp ( argv [ i ] , " --windowed " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " Windowed " , true ) ;
2014-11-22 17:00:11 +00:00
} else if ( strcmp ( argv [ i ] , " --vsync " ) = = 0 )
{
2014-11-23 16:21:36 +00:00
bool vsync = ( strcmp ( argv [ i + 1 ] , " on " ) = = 0 | | strcmp ( argv [ i + 1 ] , " 1 " ) = = 0 ) ? true : false ;
2014-11-23 15:52:37 +00:00
Settings : : getInstance ( ) - > setBool ( " VSync " , vsync ) ;
2014-11-22 17:00:11 +00:00
i + + ; // skip vsync value
2014-06-25 16:29:58 +00:00
} else if ( strcmp ( argv [ i ] , " --scrape " ) = = 0 )
{
scrape_cmdline = true ;
2017-01-22 23:28:06 +00:00
} else if ( strcmp ( argv [ i ] , " --max-vram " ) = = 0 )
{
int maxVRAM = atoi ( argv [ i + 1 ] ) ;
Settings : : getInstance ( ) - > setInt ( " MaxVRAM " , maxVRAM ) ;
2017-09-08 14:49:47 +00:00
}
else if ( strcmp ( argv [ i ] , " --force-kiosk " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " ForceKiosk " , true ) ;
2017-09-08 13:20:07 +00:00
}
else if ( strcmp ( argv [ i ] , " --force-kid " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " ForceKid " , true ) ;
}
2018-05-10 20:08:04 +00:00
else if ( strcmp ( argv [ i ] , " --force-disable-filters " ) = = 0 )
{
Settings : : getInstance ( ) - > setBool ( " ForceDisableFilters " , true ) ;
}
2017-09-08 13:20:07 +00:00
else if ( strcmp ( argv [ i ] , " --help " ) = = 0 | | strcmp ( argv [ i ] , " -h " ) = = 0 )
2014-06-25 16:29:58 +00:00
{
2014-11-25 03:08:22 +00:00
# ifdef WIN32
// This is a bit of a hack, but otherwise output will go to nowhere
// when the application is compiled with the "WINDOWS" subsystem (which we usually are).
// If you're an experienced Windows programmer and know how to do this
// the right way, please submit a pull request!
AttachConsole ( ATTACH_PARENT_PROCESS ) ;
freopen ( " CONOUT$ " , " wb " , stdout ) ;
# endif
2017-08-02 19:56:33 +00:00
std : : cout < <
2014-06-25 16:29:58 +00:00
" EmulationStation, a graphical front-end for ROM browsing. \n "
" Written by Alec \" Aloshi \" Lofquist. \n "
" Version " < < PROGRAM_VERSION_STRING < < " , built " < < PROGRAM_BUILT_STRING < < " \n \n "
" Command line arguments: \n "
" --resolution [width] [height] try and force a particular resolution \n "
" --gamelist-only skip automatic game search, only read from gamelist.xml \n "
" --ignore-gamelist ignore the gamelist (useful for troubleshooting) \n "
" --draw-framerate display the framerate \n "
" --no-exit don't show the exit option in the menu \n "
2017-01-12 19:17:53 +00:00
" --no-splash don't show the splash screen \n "
2014-11-25 02:49:11 +00:00
" --debug more logging, show console on Windows \n "
2014-06-25 16:29:58 +00:00
" --scrape scrape using command line interface \n "
" --windowed not fullscreen, should be used with --resolution \n "
2014-11-25 02:49:11 +00:00
" --vsync [1/on or 0/off] turn vsync on or off (default is on) \n "
2017-01-22 23:28:06 +00:00
" --max-vram [size] Max VRAM to use in Mb before swapping. 0 for unlimited \n "
2018-05-10 20:08:04 +00:00
" --force-kid Force the UI mode to be Kid \n "
2017-09-08 14:49:47 +00:00
" --force-kiosk Force the UI mode to be Kiosk \n "
2018-05-10 20:08:04 +00:00
" --force-disable-filters Force the UI to ignore applied filters in gamelist \n "
2014-06-25 16:29:58 +00:00
" --help, -h summon a sentient, angry tuba \n \n "
" More information available in README.md. \n " ;
return false ; //exit after printing help
}
}
return true ;
}
bool verifyHomeFolderExists ( )
{
//make sure the config directory exists
2018-01-27 20:04:08 +00:00
std : : string home = Utils : : FileSystem : : getHomePath ( ) ;
2014-06-25 16:29:58 +00:00
std : : string configDir = home + " /.emulationstation " ;
2018-01-09 22:55:09 +00:00
if ( ! Utils : : FileSystem : : exists ( configDir ) )
2014-06-25 16:29:58 +00:00
{
std : : cout < < " Creating config directory \" " < < configDir < < " \" \n " ;
2018-01-09 22:55:09 +00:00
Utils : : FileSystem : : createDirectory ( configDir ) ;
if ( ! Utils : : FileSystem : : exists ( configDir ) )
2014-06-25 16:29:58 +00:00
{
std : : cerr < < " Config directory could not be created! \n " ;
return false ;
}
}
return true ;
}
2017-08-02 19:56:33 +00:00
// Returns true if everything is OK,
2014-06-25 16:29:58 +00:00
bool loadSystemConfigFile ( const char * * errorString )
{
* errorString = NULL ;
if ( ! SystemData : : loadConfig ( ) )
{
LOG ( LogError ) < < " Error while parsing systems configuration file! " ;
* errorString = " IT LOOKS LIKE YOUR SYSTEMS CONFIGURATION FILE HAS NOT BEEN SET UP OR IS INVALID. YOU'LL NEED TO DO THIS BY HAND, UNFORTUNATELY. \n \n "
" VISIT EMULATIONSTATION.ORG FOR MORE INFORMATION. " ;
return false ;
}
if ( SystemData : : sSystemVector . size ( ) = = 0 )
{
LOG ( LogError ) < < " No systems found! Does at least one system have a game present? (check that extensions match!) \n (Also, make sure you've updated your es_systems.cfg for XML!) " ;
* errorString = " WE CAN'T FIND ANY SYSTEMS! \n "
" CHECK THAT YOUR PATHS ARE CORRECT IN THE SYSTEMS CONFIGURATION FILE, "
" AND YOUR GAME DIRECTORY HAS AT LEAST ONE GAME WITH THE CORRECT EXTENSION. \n \n "
" VISIT EMULATIONSTATION.ORG FOR MORE INFORMATION. " ;
return false ;
}
return true ;
}
//called on exit, assuming we get far enough to have the log initialized
void onExit ( )
{
Log : : close ( ) ;
}
int main ( int argc , char * argv [ ] )
{
2016-12-20 20:25:35 +00:00
srand ( ( unsigned int ) time ( NULL ) ) ;
2017-11-09 22:08:51 +00:00
std : : locale : : global ( std : : locale ( " C " ) ) ;
2014-10-18 21:31:10 +00:00
2017-12-01 17:42:27 +00:00
if ( ! parseArgs ( argc , argv ) )
2014-06-25 16:29:58 +00:00
return 0 ;
2014-11-25 02:49:11 +00:00
// only show the console on Windows if HideConsole is false
# ifdef WIN32
// MSVC has a "SubSystem" option, with two primary options: "WINDOWS" and "CONSOLE".
2017-08-02 19:56:33 +00:00
// In "WINDOWS" mode, no console is automatically created for us. This is good,
// because we can choose to only create the console window if the user explicitly
2014-11-25 02:49:11 +00:00
// asks for it, preventing it from flashing open and then closing.
// In "CONSOLE" mode, a console is always automatically created for us before we
// enter main. In this case, we can only hide the console after the fact, which
// will leave a brief flash.
// TL;DR: You should compile ES under the "WINDOWS" subsystem.
// I have no idea how this works with non-MSVC compilers.
if ( ! Settings : : getInstance ( ) - > getBool ( " HideConsole " ) )
{
// we want to show the console
// if we're compiled in "CONSOLE" mode, this is already done.
// if we're compiled in "WINDOWS" mode, no console is created for us automatically;
// the user asked for one, so make one and then hook stdin/stdout/sterr up to it
if ( AllocConsole ( ) ) // should only pass in "WINDOWS" mode
{
freopen ( " CONIN$ " , " r " , stdin ) ;
freopen ( " CONOUT$ " , " wb " , stdout ) ;
freopen ( " CONOUT$ " , " wb " , stderr ) ;
}
} else {
// we want to hide the console
// if we're compiled with the "WINDOWS" subsystem, this is already done.
2017-08-02 19:56:33 +00:00
// if we're compiled with the "CONSOLE" subsystem, a console is already created;
2014-11-25 02:49:11 +00:00
// it'll flash open, but we hide it nearly immediately
if ( GetConsoleWindow ( ) ) // should only pass in "CONSOLE" mode
ShowWindow ( GetConsoleWindow ( ) , SW_HIDE ) ;
}
# endif
2017-10-17 20:05:12 +00:00
// call this ONLY when linking with FreeImage as a static library
# ifdef FREEIMAGE_LIB
FreeImage_Initialise ( ) ;
# endif
2014-06-25 16:29:58 +00:00
//if ~/.emulationstation doesn't exist and cannot be created, bail
if ( ! verifyHomeFolderExists ( ) )
return 1 ;
//start the logger
2017-08-01 10:34:49 +00:00
Log : : init ( ) ;
2014-06-25 16:29:58 +00:00
Log : : open ( ) ;
LOG ( LogInfo ) < < " EmulationStation - v " < < PROGRAM_VERSION_STRING < < " , built " < < PROGRAM_BUILT_STRING ;
//always close the log on exit
atexit ( & onExit ) ;
Window window ;
2016-12-14 08:30:54 +00:00
SystemScreenSaver screensaver ( & window ) ;
2017-07-20 07:07:02 +00:00
PowerSaver : : init ( ) ;
2014-06-25 16:29:58 +00:00
ViewController : : init ( & window ) ;
2017-06-12 16:38:59 +00:00
CollectionSystemManager : : init ( & window ) ;
2018-02-09 17:23:58 +00:00
MameNames : : init ( ) ;
2014-06-25 16:29:58 +00:00
window . pushGui ( ViewController : : get ( ) ) ;
2019-01-31 20:19:34 +00:00
bool splashScreen = Settings : : getInstance ( ) - > getBool ( " SplashScreen " ) ;
bool splashScreenProgress = Settings : : getInstance ( ) - > getBool ( " SplashScreenProgress " ) ;
2014-06-25 16:29:58 +00:00
if ( ! scrape_cmdline )
{
2017-12-01 17:42:27 +00:00
if ( ! window . init ( ) )
2014-06-25 16:29:58 +00:00
{
LOG ( LogError ) < < " Window failed to initialize! " ;
return 1 ;
}
2014-07-04 19:42:26 +00:00
std : : string glExts = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
LOG ( LogInfo ) < < " Checking available OpenGL extensions... " ;
LOG ( LogInfo ) < < " ARB_texture_non_power_of_two: " < < ( glExts . find ( " ARB_texture_non_power_of_two " ) ! = std : : string : : npos ? " ok " : " MISSING " ) ;
2019-01-31 20:19:34 +00:00
if ( splashScreen )
{
std : : string progressText = " Loading... " ;
if ( splashScreenProgress )
progressText = " Loading system config... " ;
window . renderLoadingScreen ( progressText ) ;
}
2014-06-25 16:29:58 +00:00
}
const char * errorMsg = NULL ;
if ( ! loadSystemConfigFile ( & errorMsg ) )
{
// something went terribly wrong
if ( errorMsg = = NULL )
{
LOG ( LogError ) < < " Unknown error occured while parsing system config file. " ;
if ( ! scrape_cmdline )
Renderer : : deinit ( ) ;
return 1 ;
}
// we can't handle es_systems.cfg file problems inside ES itself, so display the error message then quit
window . pushGui ( new GuiMsgBox ( & window ,
errorMsg ,
2017-08-02 19:56:33 +00:00
" QUIT " , [ ] {
2014-06-25 16:29:58 +00:00
SDL_Event * quit = new SDL_Event ( ) ;
quit - > type = SDL_QUIT ;
SDL_PushEvent ( quit ) ;
} ) ) ;
}
//run the command line scraper then quit
if ( scrape_cmdline )
{
return run_scraper_cmdline ( ) ;
}
//dont generate joystick events while we're loading (hopefully fixes "automatically started emulator" bug)
SDL_JoystickEventState ( SDL_DISABLE ) ;
// preload what we can right away instead of waiting for the user to select it
// this makes for no delays when accessing content, but a longer startup time
ViewController : : get ( ) - > preload ( ) ;
2019-01-31 20:19:34 +00:00
if ( splashScreen & & splashScreenProgress )
window . renderLoadingScreen ( " Done. " ) ;
2014-06-25 16:29:58 +00:00
//choose which GUI to open depending on if an input configuration already exists
if ( errorMsg = = NULL )
{
2018-01-09 22:55:09 +00:00
if ( Utils : : FileSystem : : exists ( InputManager : : getConfigPath ( ) ) & & InputManager : : getInstance ( ) - > getNumConfiguredDevices ( ) > 0 )
2014-06-25 16:29:58 +00:00
{
ViewController : : get ( ) - > goToStart ( ) ;
} else {
window . pushGui ( new GuiDetectDevice ( & window , true , [ ] { ViewController : : get ( ) - > goToStart ( ) ; } ) ) ;
}
}
//generate joystick events since we're done loading
SDL_JoystickEventState ( SDL_ENABLE ) ;
int lastTime = SDL_GetTicks ( ) ;
2017-07-20 07:07:02 +00:00
int ps_time = SDL_GetTicks ( ) ;
2017-08-02 19:56:33 +00:00
2014-06-25 16:29:58 +00:00
bool running = true ;
2017-07-20 07:07:02 +00:00
2014-06-25 16:29:58 +00:00
while ( running )
{
SDL_Event event ;
2017-10-18 14:19:32 +00:00
bool ps_standby = PowerSaver : : getState ( ) & & ( int ) SDL_GetTicks ( ) - ps_time > PowerSaver : : getMode ( ) ;
2017-08-02 19:56:33 +00:00
if ( ps_standby ? SDL_WaitEventTimeout ( & event , PowerSaver : : getTimeout ( ) ) : SDL_PollEvent ( & event ) )
2014-06-25 16:29:58 +00:00
{
2017-07-20 07:07:02 +00:00
do
2014-06-25 16:29:58 +00:00
{
2017-11-08 22:22:15 +00:00
InputManager : : getInstance ( ) - > parseEvent ( event , & window ) ;
if ( event . type = = SDL_QUIT )
running = false ;
2017-07-20 07:07:02 +00:00
} while ( SDL_PollEvent ( & event ) ) ;
2017-08-02 19:56:33 +00:00
2017-08-11 17:03:12 +00:00
// triggered if exiting from SDL_WaitEvent due to event
2017-07-20 07:07:02 +00:00
if ( ps_standby )
// show as if continuing from last event
lastTime = SDL_GetTicks ( ) ;
2017-08-02 19:56:33 +00:00
2017-07-20 07:07:02 +00:00
// reset counter
ps_time = SDL_GetTicks ( ) ;
2014-06-25 16:29:58 +00:00
}
2017-08-11 17:03:12 +00:00
else if ( ps_standby )
{
// If exitting SDL_WaitEventTimeout due to timeout. Trail considering
// timeout as an event
ps_time = SDL_GetTicks ( ) ;
}
2014-06-25 16:29:58 +00:00
if ( window . isSleeping ( ) )
{
lastTime = SDL_GetTicks ( ) ;
SDL_Delay ( 1 ) ; // this doesn't need to be accurate, we're just giving up our CPU time until something wakes us up
continue ;
}
int curTime = SDL_GetTicks ( ) ;
int deltaTime = curTime - lastTime ;
lastTime = curTime ;
2017-08-11 17:03:12 +00:00
// cap deltaTime if it ever goes negative
if ( deltaTime < 0 )
2014-06-25 16:29:58 +00:00
deltaTime = 1000 ;
window . update ( deltaTime ) ;
window . render ( ) ;
Renderer : : swapBuffers ( ) ;
Log : : flush ( ) ;
}
while ( window . peekGui ( ) ! = ViewController : : get ( ) )
delete window . peekGui ( ) ;
window . deinit ( ) ;
2018-02-09 17:23:58 +00:00
MameNames : : deinit ( ) ;
2017-07-18 09:45:50 +00:00
CollectionSystemManager : : deinit ( ) ;
2014-06-25 16:29:58 +00:00
SystemData : : deleteSystems ( ) ;
2017-10-17 20:05:12 +00:00
// call this ONLY when linking with FreeImage as a static library
# ifdef FREEIMAGE_LIB
FreeImage_DeInitialise ( ) ;
# endif
2014-06-25 16:29:58 +00:00
LOG ( LogInfo ) < < " EmulationStation cleanly shutting down. " ;
return 0 ;
}