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 <SDL.h>
# include <iostream>
# include <iomanip>
# include "Renderer.h"
# include "views/ViewController.h"
# include "SystemData.h"
# include <boost/filesystem.hpp>
# include "guis/GuiDetectDevice.h"
# include "guis/GuiMsgBox.h"
# include "AudioManager.h"
# include "platform.h"
# include "Log.h"
# include "Window.h"
# include "EmulationStation.h"
# include "Settings.h"
# include "ScraperCmdLine.h"
# include <sstream>
2014-10-18 21:31:10 +00:00
# include <boost/locale.hpp>
2014-06-25 16:29:58 +00:00
2014-11-25 02:49:11 +00:00
# ifdef WIN32
# include <Windows.h>
# endif
2014-06-25 16:29:58 +00:00
namespace fs = boost : : filesystem ;
bool scrape_cmdline = false ;
bool parseArgs ( int argc , char * argv [ ] , unsigned int * width , unsigned int * height )
{
for ( int i = 1 ; i < argc ; i + + )
{
if ( strcmp ( argv [ i ] , " --resolution " ) = = 0 )
{
if ( i > = argc - 2 )
{
std : : cerr < < " Invalid resolution supplied. " ;
return false ;
}
* width = atoi ( argv [ i + 1 ] ) ;
* height = atoi ( argv [ i + 2 ] ) ;
i + = 2 ; // skip the argument value
} 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 ) ;
} 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 ) ;
2014-06-25 16:29:58 +00:00
} else if ( strcmp ( argv [ i ] , " --help " ) = = 0 | | strcmp ( argv [ i ] , " -h " ) = = 0 )
{
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
2014-06-25 16:29:58 +00:00
std : : cout < <
" 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 "
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
std : : string home = getHomePath ( ) ;
std : : string configDir = home + " /.emulationstation " ;
if ( ! fs : : exists ( configDir ) )
{
std : : cout < < " Creating config directory \" " < < configDir < < " \" \n " ;
fs : : create_directory ( configDir ) ;
if ( ! fs : : exists ( configDir ) )
{
std : : cerr < < " Config directory could not be created! \n " ;
return false ;
}
}
return true ;
}
// Returns true if everything is OK,
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 [ ] )
{
unsigned int width = 0 ;
unsigned int height = 0 ;
2014-10-18 21:31:10 +00:00
std : : locale : : global ( boost : : locale : : generator ( ) . generate ( " " ) ) ;
boost : : filesystem : : path : : imbue ( std : : locale ( ) ) ;
2014-06-25 16:29:58 +00:00
if ( ! parseArgs ( argc , argv , & width , & height ) )
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".
// 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
// 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.
// if we're compiled with the "CONSOLE" subsystem, a console is already created;
// it'll flash open, but we hide it nearly immediately
if ( GetConsoleWindow ( ) ) // should only pass in "CONSOLE" mode
ShowWindow ( GetConsoleWindow ( ) , SW_HIDE ) ;
}
# 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
Log : : open ( ) ;
LOG ( LogInfo ) < < " EmulationStation - v " < < PROGRAM_VERSION_STRING < < " , built " < < PROGRAM_BUILT_STRING ;
//always close the log on exit
atexit ( & onExit ) ;
Window window ;
ViewController : : init ( & window ) ;
window . pushGui ( ViewController : : get ( ) ) ;
if ( ! scrape_cmdline )
{
if ( ! window . init ( width , height ) )
{
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 " ) ;
2017-01-12 19:17:53 +00:00
if ( Settings : : getInstance ( ) - > getBool ( " SplashScreen " ) )
window . renderLoadingScreen ( ) ;
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 ,
" QUIT " , [ ] {
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 ( ) ;
//choose which GUI to open depending on if an input configuration already exists
if ( errorMsg = = NULL )
{
if ( fs : : exists ( InputManager : : getConfigPath ( ) ) & & InputManager : : getInstance ( ) - > getNumConfiguredDevices ( ) > 0 )
{
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 ( ) ;
bool running = true ;
while ( running )
{
SDL_Event event ;
while ( SDL_PollEvent ( & event ) )
{
switch ( event . type )
{
case SDL_JOYHATMOTION :
case SDL_JOYBUTTONDOWN :
case SDL_JOYBUTTONUP :
case SDL_KEYDOWN :
case SDL_KEYUP :
case SDL_JOYAXISMOTION :
case SDL_TEXTINPUT :
case SDL_TEXTEDITING :
case SDL_JOYDEVICEADDED :
case SDL_JOYDEVICEREMOVED :
InputManager : : getInstance ( ) - > parseEvent ( event , & window ) ;
break ;
case SDL_QUIT :
running = false ;
break ;
}
}
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 ;
// cap deltaTime at 1000
if ( deltaTime > 1000 | | deltaTime < 0 )
deltaTime = 1000 ;
window . update ( deltaTime ) ;
window . render ( ) ;
Renderer : : swapBuffers ( ) ;
Log : : flush ( ) ;
}
while ( window . peekGui ( ) ! = ViewController : : get ( ) )
delete window . peekGui ( ) ;
window . deinit ( ) ;
SystemData : : deleteSystems ( ) ;
LOG ( LogInfo ) < < " EmulationStation cleanly shutting down. " ;
return 0 ;
}