2012-04-21 21:13:50 +00:00
/* RetroArch - A frontend for libretro.
2014-01-01 00:50:59 +00:00
* Copyright ( C ) 2010 - 2014 - Hans - Kristian Arntzen
* Copyright ( C ) 2011 - 2014 - Daniel De Matteis
* Copyright ( C ) 2012 - 2014 - Michael Lelli
2014-04-12 11:25:48 +00:00
*
2012-04-21 21:13:50 +00:00
* RetroArch is free software : you can redistribute it and / or modify it under the terms
2010-05-28 16:21:33 +00:00
* of the GNU General Public License as published by the Free Software Found -
* ation , either version 3 of the License , or ( at your option ) any later version .
*
2012-04-21 21:13:50 +00:00
* RetroArch is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ;
2010-05-28 16:21:33 +00:00
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
2012-04-21 21:31:57 +00:00
* You should have received a copy of the GNU General Public License along with RetroArch .
2010-05-28 16:21:33 +00:00
* If not , see < http : //www.gnu.org/licenses/>.
*/
2011-12-24 12:46:12 +00:00
# include "boolean.h"
2012-04-05 09:47:43 +00:00
# include "libretro.h"
2010-05-26 19:27:37 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2011-09-27 13:31:25 +00:00
# include <ctype.h>
2011-10-06 21:43:48 +00:00
# include <errno.h>
2010-05-28 00:45:18 +00:00
# include "driver.h"
2010-12-24 00:26:36 +00:00
# include "file.h"
# include "general.h"
2010-12-30 12:54:49 +00:00
# include "dynamic.h"
2012-11-01 05:21:18 +00:00
# include "performance.h"
2011-12-02 00:34:02 +00:00
# include "audio/utils.h"
2011-01-03 19:46:50 +00:00
# include "record/ffemu.h"
2011-01-31 15:48:42 +00:00
# include "rewind.h"
2011-02-02 11:10:27 +00:00
# include "movie.h"
2012-03-16 22:26:57 +00:00
# include "compat/strl.h"
2011-05-15 15:16:29 +00:00
# include "screenshot.h"
2011-04-17 11:30:59 +00:00
# include "cheats.h"
2012-04-21 21:33:35 +00:00
# include "compat/getopt_rarch.h"
2013-02-09 09:36:39 +00:00
# include "compat/posix_string.h"
2014-01-06 18:42:46 +00:00
# include "input/keyboard_line.h"
2014-01-08 16:31:14 +00:00
# include "input/input_common.h"
2014-01-11 17:51:42 +00:00
# include "git_version.h"
2010-12-24 00:07:27 +00:00
2013-04-11 20:35:15 +00:00
# ifdef _WIN32
# ifdef _XBOX
# include <xtl.h>
# else
2011-02-05 19:46:58 +00:00
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
2012-03-04 22:15:25 +00:00
# endif
# include "msvc/msvc_compat.h"
2011-02-05 19:46:58 +00:00
# endif
2013-04-13 22:53:05 +00:00
// To avoid continous switching if we hold the button down, we require that the button must go from pressed,
// unpressed back to pressed to be able to toggle between then.
2012-12-17 21:45:29 +00:00
static void check_fast_forward_button ( void )
2010-08-16 16:40:17 +00:00
{
2012-12-17 21:45:29 +00:00
bool new_button_state = input_key_pressed_func ( RARCH_FAST_FORWARD_KEY ) ;
bool new_hold_button_state = input_key_pressed_func ( RARCH_FAST_FORWARD_HOLD_KEY ) ;
2010-08-16 16:40:17 +00:00
static bool old_button_state = false ;
2011-05-24 00:31:21 +00:00
static bool old_hold_button_state = false ;
2010-08-16 16:40:17 +00:00
if ( new_button_state & & ! old_button_state )
{
2013-04-13 22:53:05 +00:00
driver . nonblock_state = ! driver . nonblock_state ;
driver_set_nonblock_state ( driver . nonblock_state ) ;
2011-05-24 00:31:21 +00:00
}
else if ( old_hold_button_state ! = new_hold_button_state )
{
2013-04-13 22:53:05 +00:00
driver . nonblock_state = new_hold_button_state ;
driver_set_nonblock_state ( driver . nonblock_state ) ;
2010-08-16 16:40:17 +00:00
}
2011-05-24 00:31:21 +00:00
2010-08-16 16:40:17 +00:00
old_button_state = new_button_state ;
2011-05-24 00:31:21 +00:00
old_hold_button_state = new_hold_button_state ;
2010-08-16 16:40:17 +00:00
}
2013-09-29 16:08:11 +00:00
# if defined(HAVE_SCREENSHOTS) && !defined(_XBOX1)
2012-06-08 20:39:18 +00:00
static bool take_screenshot_viewport ( void )
{
2012-10-27 22:38:31 +00:00
struct rarch_viewport vp = { 0 } ;
video_viewport_info_func ( & vp ) ;
2012-06-08 20:39:18 +00:00
2012-10-27 22:38:31 +00:00
if ( ! vp . width | | ! vp . height )
2012-06-08 20:39:18 +00:00
return false ;
2012-10-27 22:59:12 +00:00
uint8_t * buffer = ( uint8_t * ) malloc ( vp . width * vp . height * 3 ) ;
2012-06-08 20:39:18 +00:00
if ( ! buffer )
return false ;
if ( ! video_read_viewport_func ( buffer ) )
{
free ( buffer ) ;
return false ;
}
2013-09-16 21:30:42 +00:00
const char * screenshot_dir = g_settings . screenshot_directory ;
char screenshot_path [ PATH_MAX ] ;
if ( ! * g_settings . screenshot_directory )
{
fill_pathname_basedir ( screenshot_path , g_extern . basename , sizeof ( screenshot_path ) ) ;
screenshot_dir = screenshot_path ;
}
2012-06-09 08:29:50 +00:00
// Data read from viewport is in bottom-up order, suitable for BMP.
2013-09-16 21:30:42 +00:00
if ( ! screenshot_dump ( screenshot_dir ,
2012-06-08 20:39:18 +00:00
buffer ,
2012-10-27 22:38:31 +00:00
vp . width , vp . height , vp . width * 3 , true ) )
2012-06-08 20:39:18 +00:00
{
free ( buffer ) ;
return false ;
}
2012-06-29 23:18:08 +00:00
free ( buffer ) ;
2012-06-08 20:39:18 +00:00
return true ;
}
static bool take_screenshot_raw ( void )
{
2013-04-14 21:13:39 +00:00
const void * data = g_extern . frame_cache . data ;
unsigned width = g_extern . frame_cache . width ;
unsigned height = g_extern . frame_cache . height ;
int pitch = g_extern . frame_cache . pitch ;
2012-06-08 20:39:18 +00:00
2013-09-16 21:30:42 +00:00
const char * screenshot_dir = g_settings . screenshot_directory ;
char screenshot_path [ PATH_MAX ] ;
if ( ! * g_settings . screenshot_directory )
{
fill_pathname_basedir ( screenshot_path , g_extern . basename , sizeof ( screenshot_path ) ) ;
screenshot_dir = screenshot_path ;
}
2012-06-09 08:29:50 +00:00
// Negative pitch is needed as screenshot takes bottom-up,
// but we use top-down.
2013-09-16 21:30:42 +00:00
return screenshot_dump ( screenshot_dir ,
2014-04-12 11:25:48 +00:00
( const uint8_t * ) data + ( height - 1 ) * pitch ,
2012-06-08 20:39:18 +00:00
width , height , - pitch , false ) ;
}
2013-06-16 11:44:07 +00:00
void rarch_take_screenshot ( void )
2011-05-15 15:16:29 +00:00
{
2013-09-16 21:30:42 +00:00
if ( ( ! * g_settings . screenshot_directory ) & & ( ! * g_extern . basename ) ) // No way to infer screenshot directory.
2011-05-15 15:16:29 +00:00
return ;
2011-10-23 10:38:11 +00:00
bool ret = false ;
2013-09-16 20:27:15 +00:00
bool viewport_read = ( g_settings . video . gpu_screenshot | |
g_extern . system . hw_render_callback . context_type ! = RETRO_HW_CONTEXT_NONE ) & &
driver . video - > read_viewport & &
driver . video - > viewport_info ;
// Clear out message queue to avoid OSD fonts to appear on screenshot.
msg_queue_clear ( g_extern . msg_queue ) ;
if ( viewport_read )
{
// Avoid taking screenshot of GUI overlays.
if ( driver . video_poke & & driver . video_poke - > set_texture_enable )
driver . video_poke - > set_texture_enable ( driver . video_data , false , false ) ;
if ( driver . video )
rarch_render_cached_frame ( ) ;
}
if ( viewport_read )
2013-06-21 22:38:00 +00:00
ret = take_screenshot_viewport ( ) ;
else if ( g_extern . frame_cache . data & & ( g_extern . frame_cache . data ! = RETRO_HW_FRAME_BUFFER_VALID ) )
ret = take_screenshot_raw ( ) ;
else
RARCH_ERR ( " Cannot take screenshot. GPU rendering is used and read_viewport is not supported. \n " ) ;
2011-05-15 15:16:29 +00:00
const char * msg = NULL ;
if ( ret )
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Taking screenshot. \n " ) ;
2012-02-11 19:59:41 +00:00
msg = " Taking screenshot. " ;
2011-05-15 15:16:29 +00:00
}
else
{
2012-04-21 21:25:32 +00:00
RARCH_WARN ( " Failed to take screenshot ... \n " ) ;
2012-02-11 19:59:41 +00:00
msg = " Failed to take screenshot. " ;
2011-05-15 15:16:29 +00:00
}
2011-10-23 10:38:11 +00:00
if ( g_extern . is_paused )
{
msg_queue_push ( g_extern . msg_queue , msg , 1 , 1 ) ;
2012-04-21 21:25:32 +00:00
rarch_render_cached_frame ( ) ;
2011-10-23 10:38:11 +00:00
}
else
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2011-05-15 15:16:29 +00:00
}
2012-01-26 02:00:56 +00:00
# endif
2011-05-15 15:16:29 +00:00
2012-03-21 21:47:03 +00:00
static void readjust_audio_input_rate ( void )
{
2012-03-28 22:30:50 +00:00
int avail = audio_write_avail_func ( ) ;
2012-10-16 11:57:35 +00:00
//RARCH_LOG_OUTPUT("Audio buffer is %u%% full\n",
2012-03-21 21:47:03 +00:00
// (unsigned)(100 - (avail * 100) / g_extern.audio_data.driver_buffer_size));
2013-02-04 20:46:56 +00:00
unsigned write_index = g_extern . measure_data . buffer_free_samples_count + + & ( AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1 ) ;
g_extern . measure_data . buffer_free_samples [ write_index ] = avail ;
2013-01-18 09:38:43 +00:00
2012-03-21 21:47:03 +00:00
int half_size = g_extern . audio_data . driver_buffer_size / 2 ;
int delta_mid = avail - half_size ;
double direction = ( double ) delta_mid / half_size ;
double adjust = 1.0 + g_settings . audio . rate_control_delta * direction ;
g_extern . audio_data . src_ratio = g_extern . audio_data . orig_src_ratio * adjust ;
2012-10-16 11:57:35 +00:00
//RARCH_LOG_OUTPUT("New rate: %lf, Orig rate: %lf\n",
2012-03-21 21:47:03 +00:00
// g_extern.audio_data.src_ratio, g_extern.audio_data.orig_src_ratio);
}
2012-08-25 20:38:49 +00:00
# ifdef HAVE_FFMPEG
static void recording_dump_frame ( const void * data , unsigned width , unsigned height , size_t pitch )
{
struct ffemu_video_data ffemu_data = { 0 } ;
if ( g_extern . record_gpu_buffer )
{
2012-10-27 22:38:31 +00:00
struct rarch_viewport vp = { 0 } ;
video_viewport_info_func ( & vp ) ;
if ( ! vp . width | | ! vp . height )
2012-08-25 20:38:49 +00:00
{
RARCH_WARN ( " Viewport size calculation failed! Will continue using raw data. This will probably not work right ... \n " ) ;
free ( g_extern . record_gpu_buffer ) ;
g_extern . record_gpu_buffer = NULL ;
recording_dump_frame ( data , width , height , pitch ) ;
return ;
}
2012-08-25 20:48:09 +00:00
// User has resized. We're kinda fucked now.
2012-10-27 22:38:31 +00:00
if ( vp . width ! = g_extern . record_gpu_width | | vp . height ! = g_extern . record_gpu_height )
2012-08-25 20:38:49 +00:00
{
2012-08-25 20:48:09 +00:00
static const char msg [ ] = " Recording terminated due to resize. " ;
RARCH_WARN ( " %s \n " , msg ) ;
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2012-08-25 20:38:49 +00:00
2014-02-20 21:48:31 +00:00
rarch_deinit_recording ( ) ;
2012-08-25 20:48:09 +00:00
g_extern . recording = false ;
return ;
2012-08-25 20:38:49 +00:00
}
2012-11-21 09:24:35 +00:00
// Big bottleneck.
// Since we might need to do read-backs asynchronously, it might take 3-4 times
// before this returns true ...
if ( ! video_read_viewport_func ( g_extern . record_gpu_buffer ) )
return ;
2012-08-25 20:38:49 +00:00
ffemu_data . pitch = g_extern . record_gpu_width * 3 ;
ffemu_data . width = g_extern . record_gpu_width ;
ffemu_data . height = g_extern . record_gpu_height ;
ffemu_data . data = g_extern . record_gpu_buffer + ( ffemu_data . height - 1 ) * ffemu_data . pitch ;
ffemu_data . pitch = - ffemu_data . pitch ;
}
else
{
ffemu_data . data = data ;
ffemu_data . pitch = pitch ;
ffemu_data . width = width ;
ffemu_data . height = height ;
ffemu_data . is_dupe = ! data ;
}
ffemu_push_video ( g_extern . rec , & ffemu_data ) ;
}
# endif
2012-04-05 09:47:43 +00:00
static void video_frame ( const void * data , unsigned width , unsigned height , size_t pitch )
2011-10-27 21:40:34 +00:00
{
if ( ! g_extern . video_active )
return ;
2011-05-05 12:13:12 +00:00
2013-04-22 19:10:17 +00:00
g_extern . frame_cache . data = data ;
g_extern . frame_cache . width = width ;
g_extern . frame_cache . height = height ;
g_extern . frame_cache . pitch = pitch ;
2013-05-18 15:51:10 +00:00
if ( g_extern . system . pix_fmt = = RETRO_PIXEL_FORMAT_0RGB1555 & & data & & data ! = RETRO_HW_FRAME_BUFFER_VALID )
2012-10-19 23:12:02 +00:00
{
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_INIT ( video_frame_conv ) ;
RARCH_PERFORMANCE_START ( video_frame_conv ) ;
2012-10-19 23:12:02 +00:00
driver . scaler . in_width = width ;
driver . scaler . in_height = height ;
driver . scaler . out_width = width ;
driver . scaler . out_height = height ;
driver . scaler . in_stride = pitch ;
driver . scaler . out_stride = width * sizeof ( uint16_t ) ;
scaler_ctx_scale ( & driver . scaler , driver . scaler_out , data ) ;
data = driver . scaler_out ;
pitch = driver . scaler . out_stride ;
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_STOP ( video_frame_conv ) ;
2012-10-19 23:12:02 +00:00
}
2011-08-11 03:25:31 +00:00
// Slightly messy code,
// but we really need to do processing before blocking on VSync for best possible scheduling.
2012-06-22 17:03:46 +00:00
# ifdef HAVE_FFMPEG
2012-08-25 20:38:49 +00:00
if ( g_extern . recording & & ( ! g_extern . filter . active | | ! g_settings . video . post_filter_record | | ! data | | g_extern . record_gpu_buffer ) )
recording_dump_frame ( data , width , height , pitch ) ;
2012-06-22 17:03:46 +00:00
# endif
2011-11-22 16:27:02 +00:00
2011-01-23 12:34:41 +00:00
const char * msg = msg_queue_pull ( g_extern . msg_queue ) ;
2013-03-10 20:02:10 +00:00
driver . current_msg = msg ;
2011-01-23 12:34:41 +00:00
2011-05-11 15:52:16 +00:00
# ifdef HAVE_DYLIB
2012-06-23 16:01:01 +00:00
if ( g_extern . filter . active & & data )
2010-12-30 00:33:40 +00:00
{
2012-10-21 20:58:33 +00:00
struct scaler_ctx * scaler = & g_extern . filter . scaler ;
scaler - > in_width = scaler - > out_width = width ;
scaler - > in_height = scaler - > out_height = height ;
scaler - > in_stride = pitch ;
scaler - > out_stride = width * sizeof ( uint16_t ) ;
scaler_ctx_scale ( scaler , g_extern . filter . scaler_out , data ) ;
2011-03-07 18:12:14 +00:00
unsigned owidth = width ;
unsigned oheight = height ;
g_extern . filter . psize ( & owidth , & oheight ) ;
2014-04-12 11:25:48 +00:00
g_extern . filter . prender ( g_extern . filter . colormap , g_extern . filter . buffer ,
2012-10-21 20:58:33 +00:00
g_extern . filter . pitch , g_extern . filter . scaler_out , scaler - > out_stride , width , height ) ;
2011-08-11 03:25:31 +00:00
# ifdef HAVE_FFMPEG
if ( g_extern . recording & & g_settings . video . post_filter_record )
2012-08-25 20:38:49 +00:00
recording_dump_frame ( g_extern . filter . buffer , owidth , oheight , g_extern . filter . pitch ) ;
2011-08-11 03:25:31 +00:00
# endif
2012-03-28 22:30:50 +00:00
if ( ! video_frame_func ( g_extern . filter . buffer , owidth , oheight , g_extern . filter . pitch , msg ) )
2011-03-07 16:22:03 +00:00
g_extern . video_active = false ;
2010-12-30 00:33:40 +00:00
}
2012-04-05 09:47:43 +00:00
else if ( ! video_frame_func ( data , width , height , pitch , msg ) )
2011-03-07 16:22:03 +00:00
g_extern . video_active = false ;
2010-05-29 14:59:57 +00:00
# else
2012-04-05 09:47:43 +00:00
if ( ! video_frame_func ( data , width , height , pitch , msg ) )
2010-12-29 18:18:37 +00:00
g_extern . video_active = false ;
2010-12-29 18:43:17 +00:00
# endif
2011-10-18 15:26:15 +00:00
}
2012-04-21 21:25:32 +00:00
void rarch_render_cached_frame ( void )
2011-10-18 15:26:15 +00:00
{
2011-10-18 17:16:38 +00:00
# ifdef HAVE_FFMPEG
// Cannot allow FFmpeg recording when pushing duped frames.
2011-10-18 15:26:15 +00:00
bool recording = g_extern . recording ;
g_extern . recording = false ;
2011-10-18 17:16:38 +00:00
# endif
2011-10-18 15:26:15 +00:00
2013-03-28 11:27:40 +00:00
const void * frame = g_extern . frame_cache . data ;
if ( frame = = RETRO_HW_FRAME_BUFFER_VALID )
frame = NULL ; // Dupe
2011-10-18 15:26:15 +00:00
// Not 100% safe, since the library might have
// freed the memory, but no known implementations do this :D
// It would be really stupid at any rate ...
2013-03-28 11:27:40 +00:00
video_frame ( frame ,
2012-06-22 17:03:46 +00:00
g_extern . frame_cache . width ,
g_extern . frame_cache . height ,
g_extern . frame_cache . pitch ) ;
2011-10-18 15:26:15 +00:00
2011-10-18 17:16:38 +00:00
# ifdef HAVE_FFMPEG
2011-10-18 15:26:15 +00:00
g_extern . recording = recording ;
2011-10-18 17:16:38 +00:00
# endif
2010-05-26 19:27:37 +00:00
}
2012-03-29 12:17:03 +00:00
2011-11-26 14:54:58 +00:00
static bool audio_flush ( const int16_t * data , size_t samples )
2010-05-26 19:27:37 +00:00
{
2011-06-14 19:35:31 +00:00
# ifdef HAVE_FFMPEG
if ( g_extern . recording )
{
2011-12-24 12:46:12 +00:00
struct ffemu_audio_data ffemu_data = { 0 } ;
2012-07-06 15:36:37 +00:00
ffemu_data . data = data ;
ffemu_data . frames = samples / 2 ;
2011-06-14 19:35:31 +00:00
ffemu_push_audio ( g_extern . rec , & ffemu_data ) ;
}
# endif
2012-10-13 18:22:45 +00:00
if ( g_extern . is_paused | | g_extern . audio_data . mute )
2011-10-17 19:30:58 +00:00
return true ;
2011-11-20 01:06:25 +00:00
if ( ! g_extern . audio_active )
return false ;
2011-10-17 19:30:58 +00:00
2013-02-16 11:30:26 +00:00
const float * output_data = NULL ;
2012-07-06 15:36:37 +00:00
unsigned output_frames = 0 ;
2011-10-17 19:30:58 +00:00
2012-10-13 18:22:45 +00:00
struct resampler_data src_data = { 0 } ;
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_INIT ( audio_convert_s16 ) ;
RARCH_PERFORMANCE_START ( audio_convert_s16 ) ;
2012-11-03 13:15:03 +00:00
audio_convert_s16_to_float ( g_extern . audio_data . data , data , samples ,
g_extern . audio_data . volume_gain ) ;
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_STOP ( audio_convert_s16 ) ;
2011-10-17 19:30:58 +00:00
2012-10-13 18:22:45 +00:00
# if defined(HAVE_DYLIB)
2012-04-21 21:25:32 +00:00
rarch_dsp_output_t dsp_output = { 0 } ;
2012-10-13 18:22:45 +00:00
rarch_dsp_input_t dsp_input = { 0 } ;
dsp_input . samples = g_extern . audio_data . data ;
dsp_input . frames = samples > > 1 ;
2011-05-13 19:05:28 +00:00
if ( g_extern . audio_data . dsp_plugin )
g_extern . audio_data . dsp_plugin - > process ( g_extern . audio_data . dsp_handle , & dsp_output , & dsp_input ) ;
2011-01-31 16:24:31 +00:00
2012-10-13 18:22:45 +00:00
src_data . data_in = dsp_output . samples ? dsp_output . samples : g_extern . audio_data . data ;
src_data . input_frames = dsp_output . samples ? dsp_output . frames : ( samples > > 1 ) ;
2012-06-24 11:11:10 +00:00
# else
2012-10-13 18:22:45 +00:00
src_data . data_in = g_extern . audio_data . data ;
src_data . input_frames = samples > > 1 ;
2012-06-24 11:11:10 +00:00
# endif
2012-07-06 15:36:37 +00:00
2012-10-13 18:22:45 +00:00
src_data . data_out = g_extern . audio_data . outsamples ;
2011-11-03 22:48:36 +00:00
2012-10-13 18:22:45 +00:00
if ( g_extern . audio_data . rate_control )
readjust_audio_input_rate ( ) ;
2011-05-13 19:05:28 +00:00
2012-10-13 18:22:45 +00:00
src_data . ratio = g_extern . audio_data . src_ratio ;
if ( g_extern . is_slowmotion )
src_data . ratio * = g_settings . slowmotion_ratio ;
2011-05-13 19:05:28 +00:00
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_INIT ( resampler_proc ) ;
RARCH_PERFORMANCE_START ( resampler_proc ) ;
2013-02-08 10:49:51 +00:00
rarch_resampler_process ( g_extern . audio_data . resampler ,
g_extern . audio_data . resampler_data , & src_data ) ;
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_STOP ( resampler_proc ) ;
2011-11-26 14:54:58 +00:00
2012-10-13 18:22:45 +00:00
output_data = g_extern . audio_data . outsamples ;
output_frames = src_data . output_frames ;
2012-07-06 15:36:37 +00:00
2011-05-13 19:05:28 +00:00
if ( g_extern . audio_data . use_float )
{
2012-10-13 18:22:45 +00:00
if ( audio_write_func ( output_data , output_frames * sizeof ( float ) * 2 ) < 0 )
2010-08-16 17:16:03 +00:00
{
2012-09-16 04:06:05 +00:00
RARCH_ERR ( " Audio backend failed to write. Will continue without sound. \n " ) ;
2011-10-15 11:16:32 +00:00
return false ;
2011-01-14 14:34:38 +00:00
}
2011-05-13 19:05:28 +00:00
}
else
{
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_INIT ( audio_convert_float ) ;
RARCH_PERFORMANCE_START ( audio_convert_float ) ;
2012-10-13 18:22:45 +00:00
audio_convert_float_to_s16 ( g_extern . audio_data . conv_outsamples ,
output_data , output_frames * 2 ) ;
2013-12-18 18:10:57 +00:00
RARCH_PERFORMANCE_STOP ( audio_convert_float ) ;
2010-05-26 20:42:58 +00:00
2012-10-13 18:22:45 +00:00
if ( audio_write_func ( g_extern . audio_data . conv_outsamples , output_frames * sizeof ( int16_t ) * 2 ) < 0 )
2011-05-13 19:05:28 +00:00
{
2012-09-16 04:06:05 +00:00
RARCH_ERR ( " Audio backend failed to write. Will continue without sound. \n " ) ;
2011-10-15 11:16:32 +00:00
return false ;
2011-05-13 19:05:28 +00:00
}
2010-05-26 19:27:37 +00:00
}
2011-05-13 19:05:28 +00:00
2011-10-15 11:16:32 +00:00
return true ;
}
2012-04-07 09:55:37 +00:00
static void audio_sample_rewind ( int16_t left , int16_t right )
2011-10-15 12:33:41 +00:00
{
g_extern . audio_data . rewind_buf [ - - g_extern . audio_data . rewind_ptr ] = right ;
g_extern . audio_data . rewind_buf [ - - g_extern . audio_data . rewind_ptr ] = left ;
}
2012-04-07 09:55:37 +00:00
size_t audio_sample_batch_rewind ( const int16_t * data , size_t frames )
{
2013-10-22 13:08:17 +00:00
size_t i , samples ;
samples = frames < < 1 ;
for ( i = 0 ; i < samples ; i + + )
2012-04-07 09:55:37 +00:00
g_extern . audio_data . rewind_buf [ - - g_extern . audio_data . rewind_ptr ] = data [ i ] ;
return frames ;
}
static void audio_sample ( int16_t left , int16_t right )
2011-10-15 11:16:32 +00:00
{
g_extern . audio_data . conv_outsamples [ g_extern . audio_data . data_ptr + + ] = left ;
g_extern . audio_data . conv_outsamples [ g_extern . audio_data . data_ptr + + ] = right ;
if ( g_extern . audio_data . data_ptr < g_extern . audio_data . chunk_size )
return ;
2011-10-15 12:33:41 +00:00
g_extern . audio_active = audio_flush ( g_extern . audio_data . conv_outsamples ,
2011-11-20 01:06:25 +00:00
g_extern . audio_data . data_ptr ) & & g_extern . audio_active ;
2011-10-15 12:33:41 +00:00
2011-05-13 19:05:28 +00:00
g_extern . audio_data . data_ptr = 0 ;
2010-05-26 19:27:37 +00:00
}
2012-04-07 09:55:37 +00:00
size_t audio_sample_batch ( const int16_t * data , size_t frames )
2012-03-27 20:24:46 +00:00
{
if ( frames > ( AUDIO_CHUNK_SIZE_NONBLOCKING > > 1 ) )
frames = AUDIO_CHUNK_SIZE_NONBLOCKING > > 1 ;
2012-03-29 21:19:41 +00:00
g_extern . audio_active = audio_flush ( data , frames < < 1 ) & & g_extern . audio_active ;
2012-03-27 20:24:46 +00:00
return frames ;
}
2012-12-23 17:36:58 +00:00
# ifdef HAVE_OVERLAY
2012-12-20 14:33:54 +00:00
static inline void input_poll_overlay ( void )
{
2014-01-03 17:56:21 +00:00
input_overlay_state_t old_key_state ;
memcpy ( old_key_state . keys , driver . overlay_state . keys , sizeof ( driver . overlay_state . keys ) ) ;
2013-09-05 22:19:07 +00:00
memset ( & driver . overlay_state , 0 , sizeof ( driver . overlay_state ) ) ;
2012-12-20 14:33:54 +00:00
2013-01-11 15:23:04 +00:00
unsigned device = input_overlay_full_screen ( driver . overlay ) ?
RARCH_DEVICE_POINTER_SCREEN : RETRO_DEVICE_POINTER ;
2013-02-17 14:00:38 +00:00
bool polled = false ;
2013-10-22 13:08:17 +00:00
unsigned i , j ;
for ( i = 0 ;
2013-01-11 15:23:04 +00:00
input_input_state_func ( NULL , 0 , device , i , RETRO_DEVICE_ID_POINTER_PRESSED ) ;
2012-12-27 11:26:13 +00:00
i + + )
{
int16_t x = input_input_state_func ( NULL , 0 ,
2013-01-11 15:23:04 +00:00
device , i , RETRO_DEVICE_ID_POINTER_X ) ;
2012-12-27 11:26:13 +00:00
int16_t y = input_input_state_func ( NULL , 0 ,
2013-01-11 15:23:04 +00:00
device , i , RETRO_DEVICE_ID_POINTER_Y ) ;
2012-12-20 14:33:54 +00:00
2013-09-05 22:19:07 +00:00
input_overlay_state_t polled_data ;
input_overlay_poll ( driver . overlay , & polled_data , x , y ) ;
driver . overlay_state . buttons | = polled_data . buttons ;
2014-04-12 11:25:48 +00:00
2014-01-03 17:56:21 +00:00
for ( j = 0 ; j < ARRAY_SIZE ( driver . overlay_state . keys ) ; j + + )
2014-01-02 21:41:34 +00:00
driver . overlay_state . keys [ j ] | = polled_data . keys [ j ] ;
2013-09-05 22:19:07 +00:00
2013-12-31 16:15:28 +00:00
// Fingers pressed later take prio and matched up with overlay poll priorities.
2013-12-28 14:31:25 +00:00
for ( j = 0 ; j < 4 ; j + + )
2013-12-31 16:15:28 +00:00
if ( polled_data . analog [ j ] )
2013-09-05 22:19:07 +00:00
driver . overlay_state . analog [ j ] = polled_data . analog [ j ] ;
2013-02-17 14:00:38 +00:00
polled = true ;
2012-12-27 11:26:13 +00:00
}
2013-02-17 14:00:38 +00:00
2014-01-06 18:42:46 +00:00
uint16_t key_mod = 0 ;
key_mod | = ( OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_LSHIFT ) | |
OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_RSHIFT ) ) ? RETROKMOD_SHIFT : 0 ;
key_mod | = ( OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_LCTRL ) | |
OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_RCTRL ) ) ? RETROKMOD_CTRL : 0 ;
key_mod | = ( OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_LALT ) | |
OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_RALT ) ) ? RETROKMOD_ALT : 0 ;
key_mod | = ( OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_LMETA ) | |
OVERLAY_GET_KEY ( & driver . overlay_state , RETROK_RMETA ) ) ? RETROKMOD_META : 0 ;
// CAPSLOCK SCROLLOCK NUMLOCK
2014-01-03 17:56:21 +00:00
for ( i = 0 ; i < ARRAY_SIZE ( driver . overlay_state . keys ) ; i + + )
2014-01-06 18:42:46 +00:00
{
2014-01-03 17:56:21 +00:00
if ( driver . overlay_state . keys [ i ] ! = old_key_state . keys [ i ] )
{
2014-01-06 18:42:46 +00:00
uint32_t orig_bits = old_key_state . keys [ i ] ;
uint32_t new_bits = driver . overlay_state . keys [ i ] ;
2014-04-12 11:25:48 +00:00
2014-01-03 17:56:21 +00:00
for ( j = 0 ; j < 32 ; j + + )
2014-01-06 18:42:46 +00:00
if ( ( orig_bits & ( 1 < < j ) ) ! = ( new_bits & ( 1 < < j ) ) )
input_keyboard_event ( new_bits & ( 1 < < j ) , i * 32 + j , 0 , key_mod ) ;
2014-01-03 17:56:21 +00:00
}
2014-01-06 18:42:46 +00:00
}
2014-01-03 17:56:21 +00:00
2014-01-07 16:37:59 +00:00
// Map "analog" buttons to analog axes like regular input drivers do.
for ( j = 0 ; j < 4 ; j + + )
{
if ( ! driver . overlay_state . analog [ j ] )
{
unsigned bind_plus = RARCH_ANALOG_LEFT_X_PLUS + 2 * j ;
unsigned bind_minus = bind_plus + 1 ;
driver . overlay_state . analog [ j ] + = ( driver . overlay_state . buttons & ( 1ULL < < bind_plus ) ) ? 0x7fff : 0 ;
driver . overlay_state . analog [ j ] - = ( driver . overlay_state . buttons & ( 1ULL < < bind_minus ) ) ? 0x7fff : 0 ;
}
}
2014-01-08 16:31:14 +00:00
// Check for analog_dpad_mode. Map analogs to d-pad buttons when configured.
switch ( g_settings . input . analog_dpad_mode [ 0 ] )
{
case ANALOG_DPAD_LSTICK :
case ANALOG_DPAD_RSTICK :
{
unsigned analog_base = g_settings . input . analog_dpad_mode [ 0 ] = = ANALOG_DPAD_LSTICK ?
0 : 2 ;
float analog_x = ( float ) driver . overlay_state . analog [ analog_base + 0 ] / 0x7fff ;
float analog_y = ( float ) driver . overlay_state . analog [ analog_base + 1 ] / 0x7fff ;
driver . overlay_state . buttons | = ( analog_x < = - g_settings . input . axis_threshold ) ? ( 1ULL < < RETRO_DEVICE_ID_JOYPAD_LEFT ) : 0 ;
driver . overlay_state . buttons | = ( analog_x > = g_settings . input . axis_threshold ) ? ( 1ULL < < RETRO_DEVICE_ID_JOYPAD_RIGHT ) : 0 ;
driver . overlay_state . buttons | = ( analog_y < = - g_settings . input . axis_threshold ) ? ( 1ULL < < RETRO_DEVICE_ID_JOYPAD_UP ) : 0 ;
driver . overlay_state . buttons | = ( analog_y > = g_settings . input . axis_threshold ) ? ( 1ULL < < RETRO_DEVICE_ID_JOYPAD_DOWN ) : 0 ;
break ;
}
default :
break ;
}
2013-12-27 01:37:52 +00:00
if ( polled )
2013-12-27 02:39:07 +00:00
input_overlay_post_poll ( driver . overlay ) ;
2013-12-27 01:37:52 +00:00
else
2013-02-17 14:00:38 +00:00
input_overlay_poll_clear ( driver . overlay ) ;
2012-12-20 14:33:54 +00:00
}
2012-12-23 17:36:58 +00:00
# endif
2012-12-20 14:33:54 +00:00
2013-03-16 09:35:22 +00:00
void rarch_input_poll ( void )
2010-05-26 19:27:37 +00:00
{
2012-03-28 22:30:50 +00:00
input_poll_func ( ) ;
2012-12-20 14:33:54 +00:00
2012-12-23 17:36:58 +00:00
# ifdef HAVE_OVERLAY
2012-12-20 14:33:54 +00:00
if ( driver . overlay ) // Poll overlay state
input_poll_overlay ( ) ;
2012-12-23 17:36:58 +00:00
# endif
2014-03-17 10:34:25 +00:00
# ifdef HAVE_COMMAND
if ( driver . command )
rarch_cmd_poll ( driver . command ) ;
# endif
2010-05-26 19:27:37 +00:00
}
2013-11-11 09:39:07 +00:00
# ifndef RARCH_CONSOLE
2012-10-01 20:15:48 +00:00
// Turbo scheme: If turbo button is held, all buttons pressed except for D-pad will go into
// a turbo mode. Until the button is released again, the input state will be modulated by a periodic pulse defined
// by the configured duty cycle.
static bool input_apply_turbo ( unsigned port , unsigned id , bool res )
{
if ( res & & g_extern . turbo_frame_enable [ port ] )
g_extern . turbo_enable [ port ] | = ( 1 < < id ) ;
else if ( ! res )
g_extern . turbo_enable [ port ] & = ~ ( 1 < < id ) ;
if ( g_extern . turbo_enable [ port ] & ( 1 < < id ) )
2013-10-13 08:22:23 +00:00
return res & & ( ( g_extern . turbo_count % g_settings . input . turbo_period ) < g_settings . input . turbo_duty_cycle ) ;
2012-10-01 20:15:48 +00:00
else
return res ;
}
2013-11-11 09:39:07 +00:00
# endif
2012-10-01 20:15:48 +00:00
2012-04-07 09:55:37 +00:00
static int16_t input_state ( unsigned port , unsigned device , unsigned index , unsigned id )
2010-05-26 19:27:37 +00:00
{
2012-04-07 09:55:37 +00:00
device & = RETRO_DEVICE_MASK ;
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-11-20 19:19:05 +00:00
if ( g_extern . bsv . movie & & g_extern . bsv . movie_playback )
2011-02-02 11:10:27 +00:00
{
int16_t ret ;
2011-11-20 19:19:05 +00:00
if ( bsv_movie_get_input ( g_extern . bsv . movie , & ret ) )
2011-02-02 11:10:27 +00:00
return ret ;
else
2011-11-20 19:19:05 +00:00
g_extern . bsv . movie_end = true ;
2011-02-02 11:10:27 +00:00
}
2012-03-25 22:04:12 +00:00
# endif
2011-02-02 11:10:27 +00:00
2012-07-07 15:19:32 +00:00
static const struct retro_keybind * binds [ MAX_PLAYERS ] = {
2011-06-11 18:02:17 +00:00
g_settings . input . binds [ 0 ] ,
g_settings . input . binds [ 1 ] ,
g_settings . input . binds [ 2 ] ,
g_settings . input . binds [ 3 ] ,
2012-02-04 00:54:19 +00:00
g_settings . input . binds [ 4 ] ,
g_settings . input . binds [ 5 ] ,
g_settings . input . binds [ 6 ] ,
g_settings . input . binds [ 7 ] ,
2011-06-11 18:02:17 +00:00
} ;
2011-01-10 15:53:37 +00:00
2011-10-16 13:45:04 +00:00
int16_t res = 0 ;
2012-08-12 08:01:35 +00:00
if ( id < RARCH_FIRST_META_KEY | | device = = RETRO_DEVICE_KEYBOARD )
2012-03-28 22:30:50 +00:00
res = input_input_state_func ( binds , port , device , index , id ) ;
2011-10-16 13:45:04 +00:00
2012-12-23 17:36:58 +00:00
# ifdef HAVE_OVERLAY
2012-12-20 14:33:54 +00:00
if ( device = = RETRO_DEVICE_JOYPAD & & port = = 0 )
2013-09-05 22:19:07 +00:00
res | = driver . overlay_state . buttons & ( UINT64_C ( 1 ) < < id ) ? 1 : 0 ;
2014-01-03 04:20:06 +00:00
else if ( device = = RETRO_DEVICE_KEYBOARD & & port = = 0 & & id < RETROK_LAST )
res | = OVERLAY_GET_KEY ( & driver . overlay_state , id ) ? 1 : 0 ;
2013-09-05 15:38:00 +00:00
else if ( device = = RETRO_DEVICE_ANALOG & & port = = 0 )
{
unsigned base = ( index = = RETRO_DEVICE_INDEX_ANALOG_RIGHT ) ? 2 : 0 ;
base + = ( id = = RETRO_DEVICE_ID_ANALOG_Y ) ? 1 : 0 ;
2014-01-08 12:32:51 +00:00
if ( driver . overlay_state . analog [ base ] )
res = driver . overlay_state . analog [ base ] ;
2013-09-05 15:38:00 +00:00
}
2012-12-23 17:36:58 +00:00
# endif
2012-12-20 14:33:54 +00:00
2013-11-07 03:20:20 +00:00
# ifndef RARCH_CONSOLE
2012-10-01 20:15:48 +00:00
// Don't allow turbo for D-pad.
if ( device = = RETRO_DEVICE_JOYPAD & & ( id < RETRO_DEVICE_ID_JOYPAD_UP | | id > RETRO_DEVICE_ID_JOYPAD_RIGHT ) )
res = input_apply_turbo ( port , id , res ) ;
2013-11-07 03:20:20 +00:00
# endif
2012-10-01 20:15:48 +00:00
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-11-20 19:19:05 +00:00
if ( g_extern . bsv . movie & & ! g_extern . bsv . movie_playback )
bsv_movie_set_input ( g_extern . bsv . movie , res ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-02-02 11:10:27 +00:00
return res ;
2010-05-26 19:27:37 +00:00
}
2011-01-07 16:59:53 +00:00
# ifdef _WIN32
2013-10-01 10:08:20 +00:00
# define RARCH_DEFAULT_CONF_PATH_STR "\n\t\tDefaults to retroarch.cfg in same directory as retroarch.exe.\n\t\tIf a default config is not found, RetroArch will attempt to create one."
2011-01-07 16:59:53 +00:00
# else
2013-10-04 13:38:57 +00:00
# ifndef GLOBAL_CONFIG_DIR
# define GLOBAL_CONFIG_DIR " / etc"
# endif
# define RARCH_DEFAULT_CONF_PATH_STR "\n\t\tBy default looks for config in $XDG_CONFIG_HOME / retroarch / retroarch.cfg,\n\t\t$HOME / .config / retroarch / retroarch.cfg,\n\t\tand $HOME / .retroarch.cfg.\n\t\tIf a default config is not found, RetroArch will attempt to create one based on the skeleton config (" GLOBAL_CONFIG_DIR " / retroarch.cfg)."
2011-01-07 16:59:53 +00:00
# endif
2011-01-25 12:03:53 +00:00
# include "config.features.h"
# define _PSUPP(var, name, desc) printf("\t%s:\n\t\t%s: %s\n", name, desc, _##var##_supp ? "yes" : "no")
static void print_features ( void )
{
puts ( " " ) ;
puts ( " Features: " ) ;
_PSUPP ( sdl , " SDL " , " SDL drivers " ) ;
2011-11-30 16:46:58 +00:00
_PSUPP ( thread , " Threads " , " Threading support " ) ;
2011-11-01 17:45:50 +00:00
_PSUPP ( opengl , " OpenGL " , " OpenGL driver " ) ;
2012-09-25 10:58:45 +00:00
_PSUPP ( kms , " KMS " , " KMS/EGL context support " ) ;
2013-12-08 15:07:14 +00:00
_PSUPP ( udev , " UDEV " , " UDEV/EVDEV input driver support " ) ;
2012-09-25 10:58:45 +00:00
_PSUPP ( egl , " EGL " , " EGL context support " ) ;
_PSUPP ( vg , " OpenVG " , " OpenVG output support " ) ;
2011-06-25 16:11:04 +00:00
_PSUPP ( xvideo , " XVideo " , " XVideo output " ) ;
2011-01-25 12:03:53 +00:00
_PSUPP ( alsa , " ALSA " , " audio driver " ) ;
_PSUPP ( oss , " OSS " , " audio driver " ) ;
_PSUPP ( jack , " Jack " , " audio driver " ) ;
_PSUPP ( rsound , " RSound " , " audio driver " ) ;
_PSUPP ( roar , " RoarAudio " , " audio driver " ) ;
2011-01-29 23:30:54 +00:00
_PSUPP ( pulse , " PulseAudio " , " audio driver " ) ;
2011-12-25 00:59:30 +00:00
_PSUPP ( dsound , " DirectSound " , " audio driver " ) ;
2011-01-29 23:30:54 +00:00
_PSUPP ( xaudio , " XAudio2 " , " audio driver " ) ;
2013-01-21 22:51:56 +00:00
_PSUPP ( zlib , " zlib " , " PNG encode/decode and .zip extraction " ) ;
2011-01-25 12:03:53 +00:00
_PSUPP ( al , " OpenAL " , " audio driver " ) ;
2012-12-22 10:35:26 +00:00
_PSUPP ( dylib , " External " , " External filter and plugin support " ) ;
2011-01-25 12:03:53 +00:00
_PSUPP ( cg , " Cg " , " Cg pixel shaders " ) ;
2013-01-02 14:05:55 +00:00
_PSUPP ( libxml2 , " libxml2 " , " libxml2 XML parsing " ) ;
2011-06-11 14:55:53 +00:00
_PSUPP ( sdl_image , " SDL_image " , " SDL_image image loading " ) ;
2011-03-23 22:48:13 +00:00
_PSUPP ( fbo , " FBO " , " OpenGL render-to-texture (multi-pass shaders) " ) ;
2012-04-03 17:25:53 +00:00
_PSUPP ( dynamic , " Dynamic " , " Dynamic run-time loading of libretro library " ) ;
2011-01-25 12:03:53 +00:00
_PSUPP ( ffmpeg , " FFmpeg " , " On-the-fly recording of gameplay with libavcodec " ) ;
_PSUPP ( freetype , " FreeType " , " TTF font rendering with FreeType " ) ;
2011-03-19 19:41:07 +00:00
_PSUPP ( netplay , " Netplay " , " Peer-to-peer netplay " ) ;
2011-06-06 18:21:26 +00:00
_PSUPP ( python , " Python " , " Script support in shaders " ) ;
2011-01-25 12:03:53 +00:00
}
# undef _PSUPP
2011-12-25 20:39:58 +00:00
static void print_compiler ( FILE * file )
2011-12-25 20:16:48 +00:00
{
2011-12-25 20:39:58 +00:00
fprintf ( file , " \n Compiler: " ) ;
2011-12-25 20:16:48 +00:00
# if defined(_MSC_VER)
2011-12-25 20:39:58 +00:00
fprintf ( file , " MSVC (%d) %u-bit \n " , _MSC_VER , ( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
2012-01-11 21:55:07 +00:00
# elif defined(__SNC__)
2012-01-16 15:38:27 +00:00
fprintf ( file , " SNC (%d) %u-bit \n " ,
__SN_VER__ , ( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
2011-12-25 20:16:48 +00:00
# elif defined(_WIN32) && defined(__GNUC__)
2011-12-25 20:39:58 +00:00
fprintf ( file , " MinGW (%d.%d.%d) %u-bit \n " ,
2011-12-25 20:16:48 +00:00
__GNUC__ , __GNUC_MINOR__ , __GNUC_PATCHLEVEL__ , ( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
# elif defined(__clang__)
2011-12-25 20:39:58 +00:00
fprintf ( file , " Clang/LLVM (%s) %u-bit \n " ,
2014-01-22 15:30:44 +00:00
__clang_version__ , ( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
2011-12-25 20:16:48 +00:00
# elif defined(__GNUC__)
2011-12-25 20:39:58 +00:00
fprintf ( file , " GCC (%d.%d.%d) %u-bit \n " ,
2011-12-25 20:16:48 +00:00
__GNUC__ , __GNUC_MINOR__ , __GNUC_PATCHLEVEL__ , ( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
# else
2011-12-25 20:39:58 +00:00
fprintf ( file , " Unknown compiler %u-bit \n " ,
2011-12-25 20:16:48 +00:00
( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
# endif
2011-12-25 20:39:58 +00:00
fprintf ( file , " Built: %s \n " , __DATE__ ) ;
2011-12-25 20:16:48 +00:00
}
2010-10-01 19:39:15 +00:00
static void print_help ( void )
{
2011-02-15 15:42:55 +00:00
puts ( " =================================================================== " ) ;
2014-01-11 17:51:42 +00:00
# ifdef HAVE_GIT_VERSION
printf ( " RetroArch: Frontend for libretro -- v " PACKAGE_VERSION " -- %s -- \n " , rarch_git_version ) ;
# else
2012-04-21 21:13:50 +00:00
puts ( " RetroArch: Frontend for libretro -- v " PACKAGE_VERSION " -- " ) ;
2014-01-11 17:51:42 +00:00
# endif
2011-12-25 20:39:58 +00:00
print_compiler ( stdout ) ;
2011-02-15 15:42:55 +00:00
puts ( " =================================================================== " ) ;
2012-04-23 20:43:07 +00:00
puts ( " Usage: retroarch [rom file] [options...] " ) ;
2011-06-21 20:37:48 +00:00
puts ( " \t -h/--help: Show this help message. " ) ;
2013-04-14 14:24:19 +00:00
puts ( " \t --menu: Do not require ROM or libretro core to be loaded, starts directly in menu. " ) ;
2013-04-14 20:41:43 +00:00
puts ( " \t \t If no arguments are passed to RetroArch, it is equivalent to using --menu as only argument. " ) ;
2012-04-21 21:13:50 +00:00
puts ( " \t --features: Prints available features compiled into RetroArch. " ) ;
2013-04-30 22:56:13 +00:00
puts ( " \t -s/--save: Path for save file (*.srm). " ) ;
2012-04-21 21:13:50 +00:00
puts ( " \t -f/--fullscreen: Start RetroArch in fullscreen regardless of config settings. " ) ;
2011-01-12 17:07:31 +00:00
puts ( " \t -S/--savestate: Path to use for save states. If not selected, *.state will be assumed. " ) ;
2012-04-21 21:25:32 +00:00
puts ( " \t -c/--config: Path for config file. " RARCH_DEFAULT_CONF_PATH_STR ) ;
2012-09-10 22:10:44 +00:00
puts ( " \t --appendconfig: Extra config files are loaded in, and take priority over config selected in -c (or default). " ) ;
puts ( " \t \t Multiple configs are delimited by ','. " ) ;
2011-11-15 20:15:12 +00:00
# ifdef HAVE_DYNAMIC
2012-04-03 17:25:53 +00:00
puts ( " \t -L/--libretro: Path to libretro implementation. Overrides any config setting. " ) ;
2011-01-19 11:54:19 +00:00
# endif
2014-04-04 13:13:44 +00:00
puts ( " \t --subsystem: Use a subsystem of the libretro core. Multiple ROMs are loaded as multiple arguments. " ) ;
puts ( " \t \t If a ROM is skipped, use a blank ( \" \" ) command line argument " ) ;
puts ( " \t \t ROMs must be loaded in an order which depends on the particular subsystem used. " ) ;
puts ( " \t \t See verbose log output to learn how a particular subsystem wants ROMs to be loaded. " ) ;
2012-08-16 19:20:38 +00:00
printf ( " \t -N/--nodevice: Disconnects controller device connected to port (1 to %d). \n " , MAX_PLAYERS ) ;
printf ( " \t -A/--dualanalog: Connect a DualAnalog controller to port (1 to %d). \n " , MAX_PLAYERS ) ;
2014-04-12 11:22:24 +00:00
printf ( " \t -d/--device: Connect a generic device into port of the device (1 to %d). \n " , MAX_PLAYERS ) ;
puts ( " \t \t Format is port:ID, where ID is an unsigned number corresponding to the particular device. \n " ) ;
2012-08-16 19:20:38 +00:00
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-02-02 11:10:27 +00:00
puts ( " \t -P/--bsvplay: Playback a BSV movie file. " ) ;
2011-11-18 17:03:24 +00:00
puts ( " \t -R/--bsvrecord: Start recording a BSV movie file from the beginning. " ) ;
2011-11-20 19:19:05 +00:00
puts ( " \t -M/--sram-mode: Takes an argument telling how SRAM should be handled in the session. " ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-11-18 17:03:24 +00:00
puts ( " \t \t {no,}load-{no,}save describes if SRAM should be loaded, and if SRAM should be saved. " ) ;
2011-11-20 19:19:05 +00:00
puts ( " \t \t Do note that noload-save implies that save files will be deleted and overwritten. " ) ;
2011-03-19 19:41:07 +00:00
# ifdef HAVE_NETPLAY
2011-02-13 15:40:24 +00:00
puts ( " \t -H/--host: Host netplay as player 1. " ) ;
puts ( " \t -C/--connect: Connect to netplay as player 2. " ) ;
2011-02-18 13:49:15 +00:00
puts ( " \t --port: Port used to netplay. Default is 55435. " ) ;
2011-02-15 14:32:26 +00:00
puts ( " \t -F/--frames: Sync frames when using netplay. " ) ;
2012-03-05 16:37:18 +00:00
puts ( " \t --spectate: Netplay will become spectating mode. " ) ;
2012-01-11 18:22:18 +00:00
puts ( " \t \t Host can live stream the game content to players that connect. " ) ;
puts ( " \t \t However, the client will not be able to play. Multiple clients can connect to the host. " ) ;
2012-01-21 17:12:42 +00:00
puts ( " \t --nick: Picks a nickname for use with netplay. Not mandatory. " ) ;
2011-03-19 19:41:07 +00:00
# endif
2012-06-01 13:15:06 +00:00
# ifdef HAVE_NETWORK_CMD
puts ( " \t --command: Sends a command over UDP to an already running RetroArch process. " ) ;
puts ( " \t \t Available commands are listed if command is invalid. " ) ;
# endif
2011-01-07 16:59:53 +00:00
2011-01-05 19:07:55 +00:00
# ifdef HAVE_FFMPEG
2011-10-30 10:24:16 +00:00
puts ( " \t -r/--record: Path to record video file. \n \t \t Using .mkv extension is recommended. " ) ;
2012-11-23 21:46:21 +00:00
puts ( " \t --recordconfig: Path to settings used during recording. " ) ;
2011-10-30 10:24:16 +00:00
puts ( " \t --size: Overrides output video size when recording with FFmpeg (format: WIDTHxHEIGHT). " ) ;
2011-01-05 19:07:55 +00:00
# endif
2011-06-21 20:37:48 +00:00
puts ( " \t -v/--verbose: Verbose logging. " ) ;
2011-04-23 12:47:50 +00:00
puts ( " \t -U/--ups: Specifies path for UPS patch that will be applied to ROM. " ) ;
2011-08-17 22:24:57 +00:00
puts ( " \t --bps: Specifies path for BPS patch that will be applied to ROM. " ) ;
2012-03-20 22:08:34 +00:00
puts ( " \t --ips: Specifies path for IPS patch that will be applied to ROM. " ) ;
2012-03-20 22:45:58 +00:00
puts ( " \t --no-patch: Disables all forms of rom patching. " ) ;
2012-04-21 21:13:50 +00:00
puts ( " \t -D/--detach: Detach RetroArch from the running console. Not relevant for all platforms. \n " ) ;
2010-10-01 19:39:15 +00:00
}
2011-02-11 13:27:19 +00:00
static void set_basename ( const char * path )
{
2012-04-07 09:55:37 +00:00
strlcpy ( g_extern . fullpath , path , sizeof ( g_extern . fullpath ) ) ;
2011-10-27 21:40:34 +00:00
2011-08-22 15:05:27 +00:00
strlcpy ( g_extern . basename , path , sizeof ( g_extern . basename ) ) ;
char * dst = strrchr ( g_extern . basename , ' . ' ) ;
2011-02-11 13:27:19 +00:00
if ( dst )
* dst = ' \0 ' ;
}
2014-04-04 12:58:42 +00:00
static void set_special_paths ( char * * argv , unsigned roms )
{
unsigned i ;
// First ROM is the significant one.
set_basename ( argv [ 0 ] ) ;
g_extern . subsystem_fullpaths = string_list_new ( ) ;
rarch_assert ( g_extern . subsystem_fullpaths ) ;
union string_list_elem_attr attr ;
attr . i = 0 ;
for ( i = 0 ; i < roms ; i + + )
string_list_append ( g_extern . subsystem_fullpaths , argv [ i ] , attr ) ;
// We defer SRAM path updates until we can resolve it.
// It is more complicated for special game types.
if ( ! g_extern . has_set_state_path )
fill_pathname_noext ( g_extern . savestate_name , g_extern . basename , " .state " , sizeof ( g_extern . savestate_name ) ) ;
if ( path_is_directory ( g_extern . savestate_name ) )
{
fill_pathname_dir ( g_extern . savestate_name , g_extern . basename , " .state " , sizeof ( g_extern . savestate_name ) ) ;
RARCH_LOG ( " Redirecting save state to \" %s \" . \n " , g_extern . savestate_name ) ;
}
// If this is already set,
// do not overwrite it as this was initialized before in a menu or otherwise.
if ( ! * g_settings . system_directory )
fill_pathname_basedir ( g_settings . system_directory , argv [ 0 ] , sizeof ( g_settings . system_directory ) ) ;
}
2011-08-24 13:47:39 +00:00
static void set_paths ( const char * path )
{
set_basename ( path ) ;
if ( ! g_extern . has_set_save_path )
2014-04-04 12:58:42 +00:00
fill_pathname_noext ( g_extern . savefile_name , g_extern . basename , " .srm " , sizeof ( g_extern . savefile_name ) ) ;
2011-08-24 13:47:39 +00:00
if ( ! g_extern . has_set_state_path )
fill_pathname_noext ( g_extern . savestate_name , g_extern . basename , " .state " , sizeof ( g_extern . savestate_name ) ) ;
2014-04-04 12:58:42 +00:00
if ( path_is_directory ( g_extern . savefile_name ) )
2011-08-24 13:47:39 +00:00
{
2014-04-04 12:58:42 +00:00
fill_pathname_dir ( g_extern . savefile_name , g_extern . basename , " .srm " , sizeof ( g_extern . savefile_name ) ) ;
RARCH_LOG ( " Redirecting save file to \" %s \" . \n " , g_extern . savefile_name ) ;
2011-08-24 13:47:39 +00:00
}
if ( path_is_directory ( g_extern . savestate_name ) )
{
fill_pathname_dir ( g_extern . savestate_name , g_extern . basename , " .state " , sizeof ( g_extern . savestate_name ) ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Redirecting save state to \" %s \" . \n " , g_extern . savestate_name ) ;
2011-08-24 13:47:39 +00:00
}
2011-10-28 15:10:58 +00:00
2012-11-20 11:41:25 +00:00
// If this is already set,
// do not overwrite it as this was initialized before in a menu or otherwise.
if ( ! * g_settings . system_directory )
fill_pathname_basedir ( g_settings . system_directory , path , sizeof ( g_settings . system_directory ) ) ;
2011-08-24 13:47:39 +00:00
}
2010-10-01 19:39:15 +00:00
static void parse_input ( int argc , char * argv [ ] )
2010-05-26 19:27:37 +00:00
{
2013-04-30 22:56:13 +00:00
g_extern . libretro_no_rom = false ;
2013-04-16 07:41:02 +00:00
g_extern . libretro_dummy = false ;
g_extern . has_set_save_path = false ;
g_extern . has_set_state_path = false ;
2013-12-28 22:29:34 +00:00
g_extern . has_set_libretro = false ;
2014-04-04 15:04:01 +00:00
* g_extern . subsystem = ' \0 ' ;
2013-04-16 07:41:02 +00:00
2010-10-01 19:39:15 +00:00
if ( argc < 2 )
2010-05-26 19:27:37 +00:00
{
2013-04-14 17:23:10 +00:00
g_extern . libretro_dummy = true ;
return ;
2010-05-26 19:27:37 +00:00
}
2010-05-29 13:21:30 +00:00
2012-02-01 20:32:27 +00:00
// Make sure we can call parse_input several times ...
2013-04-26 21:06:43 +00:00
optind = 0 ;
2012-02-01 20:32:27 +00:00
2011-02-18 13:49:15 +00:00
int val = 0 ;
2012-01-05 20:43:55 +00:00
const struct option opts [ ] = {
2011-11-15 20:15:12 +00:00
# ifdef HAVE_DYNAMIC
2012-04-03 17:25:53 +00:00
{ " libretro " , 1 , NULL , ' L ' } ,
2011-11-15 20:15:12 +00:00
# endif
2013-04-14 14:24:19 +00:00
{ " menu " , 0 , & val , ' M ' } ,
2010-10-01 19:39:15 +00:00
{ " help " , 0 , NULL , ' h ' } ,
{ " save " , 1 , NULL , ' s ' } ,
2011-07-09 06:37:08 +00:00
{ " fullscreen " , 0 , NULL , ' f ' } ,
2011-01-05 19:07:55 +00:00
# ifdef HAVE_FFMPEG
{ " record " , 1 , NULL , ' r ' } ,
2012-11-23 21:46:21 +00:00
{ " recordconfig " , 1 , & val , ' R ' } ,
2011-10-06 21:43:48 +00:00
{ " size " , 1 , & val , ' s ' } ,
2011-01-05 19:07:55 +00:00
# endif
2010-10-01 20:10:28 +00:00
{ " verbose " , 0 , NULL , ' v ' } ,
2012-09-09 07:26:54 +00:00
{ " config " , 1 , NULL , ' c ' } ,
2012-09-10 22:10:44 +00:00
{ " appendconfig " , 1 , & val , ' C ' } ,
2011-06-19 09:11:04 +00:00
{ " nodevice " , 1 , NULL , ' N ' } ,
2012-08-16 19:20:38 +00:00
{ " dualanalog " , 1 , NULL , ' A ' } ,
2014-04-12 11:22:24 +00:00
{ " device " , 1 , NULL , ' d ' } ,
2011-01-12 17:07:31 +00:00
{ " savestate " , 1 , NULL , ' S ' } ,
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-02-02 11:10:27 +00:00
{ " bsvplay " , 1 , NULL , ' P ' } ,
2011-11-18 17:03:24 +00:00
{ " bsvrecord " , 1 , NULL , ' R ' } ,
2011-11-20 19:19:05 +00:00
{ " sram-mode " , 1 , NULL , ' M ' } ,
2012-03-25 22:04:12 +00:00
# endif
2011-11-30 15:43:09 +00:00
# ifdef HAVE_NETPLAY
2011-02-13 15:40:24 +00:00
{ " host " , 0 , NULL , ' H ' } ,
{ " connect " , 1 , NULL , ' C ' } ,
2011-02-15 14:32:26 +00:00
{ " frames " , 1 , NULL , ' F ' } ,
2011-02-18 13:49:15 +00:00
{ " port " , 1 , & val , ' p ' } ,
2012-01-11 18:22:18 +00:00
{ " spectate " , 0 , & val , ' S ' } ,
2012-01-21 17:12:42 +00:00
{ " nick " , 1 , & val , ' N ' } ,
2012-06-01 13:15:06 +00:00
# endif
# ifdef HAVE_NETWORK_CMD
{ " command " , 1 , & val , ' c ' } ,
2011-11-30 15:43:09 +00:00
# endif
2011-03-23 22:31:33 +00:00
{ " ups " , 1 , NULL , ' U ' } ,
2011-08-17 22:24:57 +00:00
{ " bps " , 1 , & val , ' B ' } ,
2012-03-20 22:08:34 +00:00
{ " ips " , 1 , & val , ' I ' } ,
2012-03-20 22:45:58 +00:00
{ " no-patch " , 0 , & val , ' n ' } ,
2011-04-23 12:47:50 +00:00
{ " detach " , 0 , NULL , ' D ' } ,
2011-10-11 18:02:46 +00:00
{ " features " , 0 , & val , ' f ' } ,
2014-04-04 12:58:42 +00:00
{ " subsystem " , 1 , NULL , ' Z ' } ,
2010-10-01 19:39:15 +00:00
{ NULL , 0 , NULL , 0 }
} ;
2011-01-05 19:07:55 +00:00
# ifdef HAVE_FFMPEG
# define FFMPEG_RECORD_ARG "r:"
# else
# define FFMPEG_RECORD_ARG
# endif
2011-11-15 20:15:12 +00:00
# ifdef HAVE_DYNAMIC
# define DYNAMIC_ARG "L:"
# else
# define DYNAMIC_ARG
# endif
2011-11-30 15:43:09 +00:00
# ifdef HAVE_NETPLAY
# define NETPLAY_ARG "HC:F:"
# else
# define NETPLAY_ARG
# endif
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
# define BSV_MOVIE_ARG "P:R:M:"
# else
# define BSV_MOVIE_ARG
# endif
2014-04-12 12:12:06 +00:00
const char * optstring = " hs:fvS:A:c:U:DN:d: " BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG ;
2013-01-13 03:12:10 +00:00
2011-10-15 10:56:48 +00:00
for ( ; ; )
2010-05-29 13:21:30 +00:00
{
2011-02-18 13:49:15 +00:00
val = 0 ;
2011-11-30 10:48:53 +00:00
int c = getopt_long ( argc , argv , optstring , opts , NULL ) ;
2011-01-10 13:29:00 +00:00
int port ;
2010-10-01 19:39:15 +00:00
if ( c = = - 1 )
break ;
switch ( c )
{
case ' h ' :
print_help ( ) ;
exit ( 0 ) ;
2014-04-12 11:22:24 +00:00
case ' Z ' :
strlcpy ( g_extern . subsystem , optarg , sizeof ( g_extern . subsystem ) ) ;
2011-01-10 15:53:37 +00:00
break ;
2014-04-12 11:22:24 +00:00
case ' d ' :
{
struct string_list * list = string_split ( optarg , " : " ) ;
port = ( list & & list - > size = = 2 ) ? strtol ( list - > elems [ 0 ] . data , NULL , 0 ) : 0 ;
unsigned id = ( list & & list - > size = = 2 ) ? strtoul ( list - > elems [ 1 ] . data , NULL , 0 ) : 0 ;
string_list_free ( list ) ;
2011-01-10 15:53:37 +00:00
2014-04-12 11:22:24 +00:00
if ( port < 1 | | port > MAX_PLAYERS )
{
RARCH_ERR ( " Connect device to a valid port. \n " ) ;
print_help ( ) ;
rarch_fail ( 1 , " parse_input() " ) ;
}
g_settings . input . libretro_device [ port - 1 ] = id ;
g_extern . has_set_libretro_device [ port - 1 ] = true ;
2014-04-04 12:58:42 +00:00
break ;
2014-04-12 11:22:24 +00:00
}
2014-04-04 12:58:42 +00:00
2012-08-16 19:20:38 +00:00
case ' A ' :
port = strtol ( optarg , NULL , 0 ) ;
if ( port < 1 | | port > MAX_PLAYERS )
{
RARCH_ERR ( " Connect dualanalog to a valid port. \n " ) ;
print_help ( ) ;
rarch_fail ( 1 , " parse_input() " ) ;
}
2013-09-22 09:08:09 +00:00
g_settings . input . libretro_device [ port - 1 ] = RETRO_DEVICE_ANALOG ;
g_extern . has_set_libretro_device [ port - 1 ] = true ;
2012-08-16 19:20:38 +00:00
break ;
2010-10-01 19:39:15 +00:00
case ' s ' :
2014-04-04 12:58:42 +00:00
strlcpy ( g_extern . savefile_name , optarg , sizeof ( g_extern . savefile_name ) ) ;
2011-02-11 13:27:19 +00:00
g_extern . has_set_save_path = true ;
2011-01-08 18:15:18 +00:00
break ;
2011-07-09 06:37:08 +00:00
case ' f ' :
g_extern . force_fullscreen = true ;
break ;
2011-01-12 17:07:31 +00:00
case ' S ' :
2011-04-03 20:29:36 +00:00
strlcpy ( g_extern . savestate_name , optarg , sizeof ( g_extern . savestate_name ) ) ;
2011-02-11 13:27:19 +00:00
g_extern . has_set_state_path = true ;
2010-10-01 19:39:15 +00:00
break ;
2010-10-01 20:10:28 +00:00
case ' v ' :
2010-12-29 18:43:17 +00:00
g_extern . verbose = true ;
2010-10-01 20:10:28 +00:00
break ;
2011-06-19 09:11:04 +00:00
case ' N ' :
port = strtol ( optarg , NULL , 0 ) ;
2012-08-16 19:20:38 +00:00
if ( port < 1 | | port > MAX_PLAYERS )
2011-06-19 09:11:04 +00:00
{
2012-08-16 19:20:38 +00:00
RARCH_ERR ( " Disconnect device from a valid port. \n " ) ;
2011-06-19 09:11:04 +00:00
print_help ( ) ;
2012-04-21 21:25:32 +00:00
rarch_fail ( 1 , " parse_input() " ) ;
2011-06-19 09:11:04 +00:00
}
2013-09-22 09:08:09 +00:00
g_settings . input . libretro_device [ port - 1 ] = RETRO_DEVICE_NONE ;
g_extern . has_set_libretro_device [ port - 1 ] = true ;
2011-06-19 09:11:04 +00:00
break ;
2010-12-29 20:12:56 +00:00
case ' c ' :
2011-04-03 20:29:36 +00:00
strlcpy ( g_extern . config_path , optarg , sizeof ( g_extern . config_path ) ) ;
2010-12-29 20:12:56 +00:00
break ;
2011-01-05 19:07:55 +00:00
# ifdef HAVE_FFMPEG
case ' r ' :
2011-04-03 20:29:36 +00:00
strlcpy ( g_extern . record_path , optarg , sizeof ( g_extern . record_path ) ) ;
2011-01-05 19:07:55 +00:00
g_extern . recording = true ;
break ;
# endif
2011-11-15 20:15:12 +00:00
# ifdef HAVE_DYNAMIC
case ' L ' :
2012-04-07 10:17:40 +00:00
strlcpy ( g_settings . libretro , optarg , sizeof ( g_settings . libretro ) ) ;
2013-12-28 22:29:34 +00:00
g_extern . has_set_libretro = true ;
2011-11-15 20:15:12 +00:00
break ;
# endif
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-02-02 11:10:27 +00:00
case ' P ' :
2011-11-20 19:19:05 +00:00
case ' R ' :
strlcpy ( g_extern . bsv . movie_start_path , optarg ,
sizeof ( g_extern . bsv . movie_start_path ) ) ;
g_extern . bsv . movie_start_playback = c = = ' P ' ;
g_extern . bsv . movie_start_recording = c = = ' R ' ;
2011-11-18 17:03:24 +00:00
break ;
2011-11-20 19:19:05 +00:00
case ' M ' :
2011-11-18 17:03:24 +00:00
if ( strcmp ( optarg , " noload-nosave " ) = = 0 )
{
2011-11-20 19:19:05 +00:00
g_extern . sram_load_disable = true ;
g_extern . sram_save_disable = true ;
2011-11-18 17:03:24 +00:00
}
else if ( strcmp ( optarg , " noload-save " ) = = 0 )
2011-11-20 19:19:05 +00:00
g_extern . sram_load_disable = true ;
2011-11-18 17:03:24 +00:00
else if ( strcmp ( optarg , " load-nosave " ) = = 0 )
2011-11-20 19:19:05 +00:00
g_extern . sram_save_disable = true ;
else if ( strcmp ( optarg , " load-save " ) ! = 0 )
2011-11-18 17:03:24 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Invalid argument in --sram-mode. \n " ) ;
2011-11-18 17:03:24 +00:00
print_help ( ) ;
2012-04-21 21:25:32 +00:00
rarch_fail ( 1 , " parse_input() " ) ;
2011-11-18 17:03:24 +00:00
}
2011-02-02 11:10:27 +00:00
break ;
2012-03-25 22:04:12 +00:00
# endif
2011-02-02 11:10:27 +00:00
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2011-02-13 15:40:24 +00:00
case ' H ' :
g_extern . netplay_enable = true ;
break ;
case ' C ' :
g_extern . netplay_enable = true ;
2011-04-03 20:29:36 +00:00
strlcpy ( g_extern . netplay_server , optarg , sizeof ( g_extern . netplay_server ) ) ;
2011-02-13 15:40:24 +00:00
break ;
2011-02-15 14:32:26 +00:00
case ' F ' :
g_extern . netplay_sync_frames = strtol ( optarg , NULL , 0 ) ;
break ;
2011-11-30 15:41:00 +00:00
# endif
2011-02-15 14:32:26 +00:00
2011-03-23 22:31:33 +00:00
case ' U ' :
2011-04-03 20:29:36 +00:00
strlcpy ( g_extern . ups_name , optarg , sizeof ( g_extern . ups_name ) ) ;
2011-08-17 22:24:57 +00:00
g_extern . ups_pref = true ;
2011-03-23 22:31:33 +00:00
break ;
2011-04-23 12:47:50 +00:00
case ' D ' :
2012-01-05 12:30:13 +00:00
# if defined(_WIN32) && !defined(_XBOX)
2011-04-23 12:47:50 +00:00
FreeConsole ( ) ;
# endif
break ;
2011-03-23 22:31:33 +00:00
2011-02-18 13:49:15 +00:00
case 0 :
switch ( val )
{
2013-04-14 14:24:19 +00:00
case ' M ' :
g_extern . libretro_dummy = true ;
break ;
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2011-02-18 13:49:15 +00:00
case ' p ' :
2011-08-24 13:47:39 +00:00
g_extern . netplay_port = strtoul ( optarg , NULL , 0 ) ;
2011-02-18 13:49:15 +00:00
break ;
2012-01-11 18:22:18 +00:00
case ' S ' :
g_extern . netplay_is_spectate = true ;
break ;
2012-01-21 17:12:42 +00:00
case ' N ' :
strlcpy ( g_extern . netplay_nick , optarg , sizeof ( g_extern . netplay_nick ) ) ;
break ;
2011-11-30 15:41:00 +00:00
# endif
2011-10-06 21:43:48 +00:00
2012-06-01 13:15:06 +00:00
# ifdef HAVE_NETWORK_CMD
case ' c ' :
if ( network_cmd_send ( optarg ) )
exit ( 0 ) ;
else
rarch_fail ( 1 , " network_cmd_send() " ) ;
break ;
# endif
2012-09-10 22:10:44 +00:00
case ' C ' :
strlcpy ( g_extern . append_config_path , optarg , sizeof ( g_extern . append_config_path ) ) ;
break ;
2011-08-17 22:24:57 +00:00
case ' B ' :
strlcpy ( g_extern . bps_name , optarg , sizeof ( g_extern . bps_name ) ) ;
g_extern . bps_pref = true ;
break ;
2011-10-06 21:43:48 +00:00
2012-03-20 22:08:34 +00:00
case ' I ' :
strlcpy ( g_extern . ips_name , optarg , sizeof ( g_extern . ips_name ) ) ;
g_extern . ips_pref = true ;
break ;
2012-03-20 22:45:58 +00:00
case ' n ' :
g_extern . block_patch = true ;
break ;
2011-10-06 21:43:48 +00:00
# ifdef HAVE_FFMPEG
case ' s ' :
{
2014-02-07 08:35:46 +00:00
if ( sscanf ( optarg , " %ux%u " , & g_extern . record_width , & g_extern . record_height ) ! = 2 )
2011-10-06 21:43:48 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Wrong format for --size. \n " ) ;
2011-10-06 21:43:48 +00:00
print_help ( ) ;
2012-04-21 21:25:32 +00:00
rarch_fail ( 1 , " parse_input() " ) ;
2011-10-06 21:43:48 +00:00
}
break ;
}
2012-11-23 21:46:21 +00:00
case ' R ' :
strlcpy ( g_extern . record_config , optarg , sizeof ( g_extern . record_config ) ) ;
break ;
2011-10-06 21:43:48 +00:00
# endif
2011-10-11 18:02:46 +00:00
case ' f ' :
print_features ( ) ;
exit ( 0 ) ;
2011-10-06 21:43:48 +00:00
2011-02-18 13:49:15 +00:00
default :
break ;
}
break ;
2010-10-01 19:39:15 +00:00
case ' ? ' :
print_help ( ) ;
2012-04-21 21:25:32 +00:00
rarch_fail ( 1 , " parse_input() " ) ;
2010-10-01 19:39:15 +00:00
default :
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Error parsing arguments. \n " ) ;
rarch_fail ( 1 , " parse_input() " ) ;
2010-10-01 19:39:15 +00:00
}
2010-05-29 13:21:30 +00:00
}
2013-04-14 14:24:19 +00:00
if ( g_extern . libretro_dummy )
{
if ( optind < argc )
{
RARCH_ERR ( " --menu was used, but ROM file was passed as well. \n " ) ;
rarch_fail ( 1 , " parse_input() " ) ;
}
}
2014-04-04 12:58:42 +00:00
else if ( ! * g_extern . subsystem & & optind < argc )
2011-08-24 13:47:39 +00:00
set_paths ( argv [ optind ] ) ;
2014-04-04 12:58:42 +00:00
else if ( * g_extern . subsystem & & optind < argc )
set_special_paths ( argv + optind , argc - optind ) ;
2011-08-24 13:47:39 +00:00
else
2013-04-30 22:56:13 +00:00
g_extern . libretro_no_rom = true ;
2013-04-16 10:22:27 +00:00
// Copy SRM/state dirs used, so they can be reused on reentrancy.
2014-04-04 12:58:42 +00:00
if ( g_extern . has_set_save_path & & path_is_directory ( g_extern . savefile_name ) )
strlcpy ( g_extern . savefile_dir , g_extern . savefile_name , sizeof ( g_extern . savefile_dir ) ) ;
2013-04-16 10:22:27 +00:00
if ( g_extern . has_set_state_path & & path_is_directory ( g_extern . savestate_name ) )
strlcpy ( g_extern . savestate_dir , g_extern . savestate_name , sizeof ( g_extern . savestate_dir ) ) ;
2010-10-01 19:39:15 +00:00
}
2010-08-15 08:02:04 +00:00
2011-01-10 13:29:00 +00:00
static void init_controllers ( void )
{
2013-10-22 13:08:17 +00:00
unsigned i ;
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2012-08-16 19:20:38 +00:00
{
2013-09-22 09:08:09 +00:00
unsigned device = g_settings . input . libretro_device [ i ] ;
2013-04-27 10:32:03 +00:00
// This is default, don't bother.
if ( device = = RETRO_DEVICE_JOYPAD )
continue ;
pretro_set_controller_port_device ( i , device ) ;
2014-04-12 11:22:24 +00:00
const struct retro_controller_description * desc = NULL ;
if ( i < g_extern . system . num_ports )
desc = libretro_find_controller_description ( & g_extern . system . ports [ i ] , device ) ;
2012-08-16 19:20:38 +00:00
2014-04-12 11:22:24 +00:00
const char * ident = desc ? desc - > desc : NULL ;
2013-04-27 10:32:03 +00:00
2014-04-12 11:22:24 +00:00
if ( ! ident )
{
switch ( device )
{
case RETRO_DEVICE_ANALOG : ident = " analog " ; break ;
default : ident = " Unknown " ; break ;
}
2013-04-27 10:32:03 +00:00
}
2014-04-12 11:22:24 +00:00
if ( device = = RETRO_DEVICE_NONE )
RARCH_LOG ( " Disconnecting device from port %u. \n " , i + 1 ) ;
else
2014-04-12 11:25:48 +00:00
RARCH_LOG ( " Connecting %s (ID: %u) to port %u. \n " , ident , device , i + 1 ) ;
2011-01-10 13:29:00 +00:00
}
}
2011-01-12 20:57:55 +00:00
static inline void load_save_files ( void )
2011-01-12 18:09:24 +00:00
{
2014-04-04 12:58:42 +00:00
unsigned i ;
if ( ! g_extern . savefiles )
return ;
2011-01-12 20:57:55 +00:00
2014-04-04 12:58:42 +00:00
for ( i = 0 ; i < g_extern . savefiles - > size ; i + + )
load_ram_file ( g_extern . savefiles - > elems [ i ] . data , g_extern . savefiles - > elems [ i ] . attr . i ) ;
2011-01-12 18:09:24 +00:00
}
2011-01-12 20:57:55 +00:00
static inline void save_files ( void )
2011-01-12 18:09:24 +00:00
{
2014-04-04 12:58:42 +00:00
unsigned i ;
if ( ! g_extern . savefiles )
return ;
2011-01-12 18:09:24 +00:00
2014-04-04 12:58:42 +00:00
for ( i = 0 ; i < g_extern . savefiles - > size ; i + + )
{
unsigned type = g_extern . savefiles - > elems [ i ] . attr . i ;
const char * path = g_extern . savefiles - > elems [ i ] . data ;
RARCH_LOG ( " Saving RAM type #%u to \" %s \" . \n " , type , path ) ;
save_ram_file ( path , type ) ;
2011-01-12 20:57:55 +00:00
}
2011-01-12 17:05:57 +00:00
}
# ifdef HAVE_FFMPEG
2014-02-20 21:48:31 +00:00
void rarch_init_recording ( void )
2011-01-12 17:05:57 +00:00
{
2011-11-05 12:34:41 +00:00
if ( ! g_extern . recording )
return ;
2011-08-11 03:25:31 +00:00
2013-03-28 11:27:40 +00:00
if ( ! g_settings . video . gpu_record & & g_extern . system . hw_render_callback . context_type )
{
RARCH_WARN ( " Libretro core is hardware rendered. Must use post-shaded FFmpeg recording as well. \n " ) ;
2013-12-21 14:41:06 +00:00
g_extern . recording = false ;
2013-03-28 11:27:40 +00:00
return ;
}
2012-04-07 09:55:37 +00:00
double fps = g_extern . system . av_info . timing . fps ;
double samplerate = g_extern . system . av_info . timing . sample_rate ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Custom timing given: FPS: %.4f, Sample rate: %.4f \n " , ( float ) fps , ( float ) samplerate ) ;
2011-11-16 17:56:42 +00:00
2011-12-24 12:46:12 +00:00
struct ffemu_params params = { 0 } ;
2012-04-07 09:55:37 +00:00
const struct retro_system_av_info * info = & g_extern . system . av_info ;
params . out_width = info - > geometry . base_width ;
params . out_height = info - > geometry . base_height ;
params . fb_width = info - > geometry . max_width ;
params . fb_height = info - > geometry . max_height ;
params . channels = 2 ;
params . filename = g_extern . record_path ;
params . fps = fps ;
2011-12-24 12:46:12 +00:00
params . samplerate = samplerate ;
2012-10-19 23:12:02 +00:00
params . pix_fmt = g_extern . system . pix_fmt = = RETRO_PIXEL_FORMAT_XRGB8888 ? FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565 ;
2012-11-23 21:46:21 +00:00
params . config = * g_extern . record_config ? g_extern . record_config : NULL ;
2011-08-11 03:25:31 +00:00
2012-08-25 20:38:49 +00:00
if ( g_settings . video . gpu_record & & driver . video - > read_viewport )
2011-11-05 12:34:41 +00:00
{
2012-10-27 22:38:31 +00:00
struct rarch_viewport vp = { 0 } ;
video_viewport_info_func ( & vp ) ;
2012-08-25 20:38:49 +00:00
2012-10-27 22:38:31 +00:00
if ( ! vp . width | | ! vp . height )
2012-08-25 20:38:49 +00:00
{
RARCH_ERR ( " Failed to get viewport information from video driver. "
" Cannot start recording ... \n " ) ;
g_extern . recording = false ;
return ;
}
2014-02-20 21:48:31 +00:00
params . out_width = vp . width ;
params . out_height = vp . height ;
params . fb_width = next_pow2 ( vp . width ) ;
params . fb_height = next_pow2 ( vp . height ) ;
2012-10-27 22:38:31 +00:00
2013-03-17 21:05:15 +00:00
if ( g_settings . video . force_aspect & & ( g_extern . system . aspect_ratio > 0.0f ) )
params . aspect_ratio = g_extern . system . aspect_ratio ;
2012-10-27 22:38:31 +00:00
else
params . aspect_ratio = ( float ) vp . width / vp . height ;
2012-08-25 20:38:49 +00:00
params . pix_fmt = FFEMU_PIX_BGR24 ;
2012-10-27 22:38:31 +00:00
g_extern . record_gpu_width = vp . width ;
g_extern . record_gpu_height = vp . height ;
2012-08-25 20:38:49 +00:00
RARCH_LOG ( " Detected viewport of %u x %u \n " ,
2012-10-27 22:38:31 +00:00
vp . width , vp . height ) ;
2012-08-25 20:38:49 +00:00
2012-10-27 22:38:31 +00:00
g_extern . record_gpu_buffer = ( uint8_t * ) malloc ( vp . width * vp . height * 3 ) ;
2012-08-25 20:38:49 +00:00
if ( ! g_extern . record_gpu_buffer )
{
RARCH_ERR ( " Failed to allocate GPU record buffer. \n " ) ;
g_extern . recording = false ;
return ;
}
2011-11-05 12:34:41 +00:00
}
2012-08-25 20:38:49 +00:00
else
2011-11-05 12:34:41 +00:00
{
2012-08-25 20:38:49 +00:00
if ( g_extern . record_width | | g_extern . record_height )
{
params . out_width = g_extern . record_width ;
params . out_height = g_extern . record_height ;
}
2011-10-14 09:00:31 +00:00
2013-03-17 21:05:15 +00:00
if ( g_settings . video . force_aspect & & ( g_extern . system . aspect_ratio > 0.0f ) )
params . aspect_ratio = g_extern . system . aspect_ratio ;
2012-08-25 20:38:49 +00:00
else
params . aspect_ratio = ( float ) params . out_width / params . out_height ;
2011-08-11 03:25:31 +00:00
2012-08-25 20:38:49 +00:00
if ( g_settings . video . post_filter_record & & g_extern . filter . active )
{
g_extern . filter . psize ( & params . out_width , & params . out_height ) ;
params . pix_fmt = FFEMU_PIX_ARGB8888 ;
unsigned max_width = params . fb_width ;
unsigned max_height = params . fb_height ;
g_extern . filter . psize ( & max_width , & max_height ) ;
params . fb_width = next_pow2 ( max_width ) ;
params . fb_height = next_pow2 ( max_height ) ;
}
2011-11-05 12:34:41 +00:00
}
2012-08-25 20:38:49 +00:00
RARCH_LOG ( " Recording with FFmpeg to %s @ %ux%u. (FB size: %ux%u pix_fmt: %u) \n " ,
2012-05-29 23:20:14 +00:00
g_extern . record_path ,
params . out_width , params . out_height ,
params . fb_width , params . fb_height ,
2012-08-25 20:38:49 +00:00
( unsigned ) params . pix_fmt ) ;
2012-05-29 23:20:14 +00:00
2011-11-05 12:34:41 +00:00
g_extern . rec = ffemu_new ( & params ) ;
if ( ! g_extern . rec )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to start FFmpeg recording. \n " ) ;
2011-11-05 12:34:41 +00:00
g_extern . recording = false ;
2012-08-25 20:38:49 +00:00
free ( g_extern . record_gpu_buffer ) ;
g_extern . record_gpu_buffer = NULL ;
2011-01-12 17:05:57 +00:00
}
}
2014-02-20 21:48:31 +00:00
void rarch_deinit_recording ( void )
2011-01-12 17:05:57 +00:00
{
2012-11-23 21:46:21 +00:00
if ( ! g_extern . recording )
return ;
2012-08-25 20:38:49 +00:00
2012-11-23 21:46:21 +00:00
ffemu_finalize ( g_extern . rec ) ;
ffemu_free ( g_extern . rec ) ;
g_extern . rec = NULL ;
free ( g_extern . record_gpu_buffer ) ;
g_extern . record_gpu_buffer = NULL ;
2011-01-12 17:05:57 +00:00
}
# endif
2012-05-28 21:30:29 +00:00
void rarch_init_msg_queue ( void )
2011-01-23 01:23:20 +00:00
{
2012-05-22 13:34:53 +00:00
if ( g_extern . msg_queue )
return ;
2012-04-21 21:25:32 +00:00
rarch_assert ( g_extern . msg_queue = msg_queue_new ( 8 ) ) ;
2011-01-23 01:23:20 +00:00
}
2012-05-29 23:20:14 +00:00
void rarch_deinit_msg_queue ( void )
2011-01-23 01:23:20 +00:00
{
if ( g_extern . msg_queue )
2012-05-22 13:34:53 +00:00
{
2011-01-23 01:23:20 +00:00
msg_queue_free ( g_extern . msg_queue ) ;
2012-05-22 13:34:53 +00:00
g_extern . msg_queue = NULL ;
}
2011-01-23 01:23:20 +00:00
}
2011-04-17 11:30:59 +00:00
static void init_cheats ( void )
{
if ( * g_settings . cheat_database )
g_extern . cheat = cheat_manager_new ( g_settings . cheat_database ) ;
}
static void deinit_cheats ( void )
{
if ( g_extern . cheat )
cheat_manager_free ( g_extern . cheat ) ;
}
2013-03-16 13:28:10 +00:00
void rarch_init_rewind ( void )
2011-01-31 15:48:42 +00:00
{
2013-03-16 13:28:10 +00:00
if ( ! g_settings . rewind_enable | | g_extern . state_manager )
2011-12-27 17:19:45 +00:00
return ;
2013-09-14 15:26:10 +00:00
if ( g_extern . system . audio_callback . callback )
2013-07-14 11:09:53 +00:00
{
RARCH_ERR ( " Implementation uses threaded audio. Cannot use rewind. \n " ) ;
return ;
}
2012-04-07 09:55:37 +00:00
g_extern . state_size = pretro_serialize_size ( ) ;
2012-11-09 19:26:12 +00:00
if ( ! g_extern . state_size )
{
RARCH_ERR ( " Implementation does not support save states. Cannot use rewind. \n " ) ;
return ;
}
2011-12-27 17:19:45 +00:00
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Initing rewind buffer with size: %u MB \n " , ( unsigned ) ( g_settings . rewind_buffer_size / 1000000 ) ) ;
2014-02-18 07:40:16 +00:00
g_extern . state_manager = state_manager_new ( g_extern . state_size , g_settings . rewind_buffer_size ) ;
2011-12-27 17:19:45 +00:00
if ( ! g_extern . state_manager )
2012-04-21 21:25:32 +00:00
RARCH_WARN ( " Failed to init rewind buffer. Rewinding will be disabled. \n " ) ;
2014-02-18 08:04:16 +00:00
2014-02-21 20:42:05 +00:00
void * state ;
state_manager_push_where ( g_extern . state_manager , & state ) ;
2014-02-18 08:04:16 +00:00
pretro_serialize ( state , g_extern . state_size ) ;
state_manager_push_do ( g_extern . state_manager ) ;
2011-01-31 15:48:42 +00:00
}
2013-03-16 13:28:10 +00:00
void rarch_deinit_rewind ( void )
2011-01-31 15:48:42 +00:00
{
if ( g_extern . state_manager )
state_manager_free ( g_extern . state_manager ) ;
2012-12-25 18:46:19 +00:00
g_extern . state_manager = NULL ;
2011-01-31 15:48:42 +00:00
}
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-02-02 11:10:27 +00:00
static void init_movie ( void )
{
2011-11-20 19:19:05 +00:00
if ( g_extern . bsv . movie_start_playback )
2011-02-02 11:45:56 +00:00
{
2012-04-21 21:25:32 +00:00
g_extern . bsv . movie = bsv_movie_init ( g_extern . bsv . movie_start_path , RARCH_MOVIE_PLAYBACK ) ;
2011-11-20 19:19:05 +00:00
if ( ! g_extern . bsv . movie )
2011-02-02 11:45:56 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to load movie file: \" %s \" . \n " , g_extern . bsv . movie_start_path ) ;
rarch_fail ( 1 , " init_movie() " ) ;
2011-02-02 11:45:56 +00:00
}
2011-11-20 19:19:05 +00:00
g_extern . bsv . movie_playback = true ;
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Starting movie playback. " , 2 , 180 ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Starting movie playback. \n " ) ;
2011-12-16 09:19:45 +00:00
g_settings . rewind_granularity = 1 ;
2011-02-02 11:45:56 +00:00
}
2011-11-20 19:19:05 +00:00
else if ( g_extern . bsv . movie_start_recording )
2011-11-18 17:03:24 +00:00
{
2012-01-02 12:32:25 +00:00
char msg [ PATH_MAX ] ;
2012-02-11 19:59:41 +00:00
snprintf ( msg , sizeof ( msg ) , " Starting movie record to \" %s \" . " ,
2011-11-20 19:19:05 +00:00
g_extern . bsv . movie_start_path ) ;
2011-11-19 00:33:21 +00:00
2012-04-21 21:25:32 +00:00
g_extern . bsv . movie = bsv_movie_init ( g_extern . bsv . movie_start_path , RARCH_MOVIE_RECORD ) ;
2011-11-18 17:03:24 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
2011-11-20 19:19:05 +00:00
msg_queue_push ( g_extern . msg_queue ,
2012-02-11 19:59:41 +00:00
g_extern . bsv . movie ? msg : " Failed to start movie record. " , 1 , 180 ) ;
2011-11-18 17:03:24 +00:00
2011-11-20 19:19:05 +00:00
if ( g_extern . bsv . movie )
2011-12-16 09:19:45 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Starting movie record to \" %s \" . \n " , g_extern . bsv . movie_start_path ) ;
2011-12-16 09:19:45 +00:00
g_settings . rewind_granularity = 1 ;
}
2011-11-18 17:03:24 +00:00
else
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to start movie record. \n " ) ;
2011-11-18 17:03:24 +00:00
}
2011-02-02 11:10:27 +00:00
}
static void deinit_movie ( void )
{
2011-11-20 19:19:05 +00:00
if ( g_extern . bsv . movie )
bsv_movie_free ( g_extern . bsv . movie ) ;
2011-02-02 11:10:27 +00:00
}
2012-03-25 22:04:12 +00:00
# endif
2011-02-02 11:10:27 +00:00
2012-04-21 21:25:32 +00:00
# define RARCH_DEFAULT_PORT 55435
2011-02-18 13:49:15 +00:00
2011-03-19 19:41:07 +00:00
# ifdef HAVE_NETPLAY
2011-02-13 15:40:24 +00:00
static void init_netplay ( void )
{
2011-11-03 20:05:12 +00:00
if ( ! g_extern . netplay_enable )
return ;
2012-05-03 22:45:53 +00:00
# ifdef HAVE_BSV_MOVIE
if ( g_extern . bsv . movie_start_playback )
{
RARCH_WARN ( " Movie playback has started. Cannot start netplay. \n " ) ;
return ;
}
# endif
2012-04-07 09:55:37 +00:00
struct retro_callbacks cbs = { 0 } ;
2011-12-24 12:46:12 +00:00
cbs . frame_cb = video_frame ;
cbs . sample_cb = audio_sample ;
2012-04-07 09:55:37 +00:00
cbs . sample_batch_cb = audio_sample_batch ;
2011-12-24 12:46:12 +00:00
cbs . state_cb = input_state ;
2011-11-03 20:05:12 +00:00
if ( * g_extern . netplay_server )
2011-02-13 15:40:24 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Connecting to netplay host... \n " ) ;
2011-11-03 20:05:12 +00:00
g_extern . netplay_is_client = true ;
}
else
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Waiting for client... \n " ) ;
2011-02-13 16:45:14 +00:00
2011-11-03 20:05:12 +00:00
g_extern . netplay = netplay_new ( g_extern . netplay_is_client ? g_extern . netplay_server : NULL ,
2012-04-21 21:25:32 +00:00
g_extern . netplay_port ? g_extern . netplay_port : RARCH_DEFAULT_PORT ,
2012-01-21 17:12:42 +00:00
g_extern . netplay_sync_frames , & cbs , g_extern . netplay_is_spectate ,
g_extern . netplay_nick ) ;
2011-11-03 20:05:12 +00:00
if ( ! g_extern . netplay )
{
g_extern . netplay_is_client = false ;
2012-04-21 21:25:32 +00:00
RARCH_WARN ( " Failed to init netplay ... \n " ) ;
2011-02-13 16:45:14 +00:00
2011-11-03 20:05:12 +00:00
if ( g_extern . msg_queue )
2011-02-13 16:45:14 +00:00
{
2011-11-03 20:05:12 +00:00
msg_queue_push ( g_extern . msg_queue ,
" Failed to init netplay ... " ,
0 , 180 ) ;
2011-02-13 16:45:14 +00:00
}
2011-02-13 15:40:24 +00:00
}
}
static void deinit_netplay ( void )
{
if ( g_extern . netplay )
netplay_free ( g_extern . netplay ) ;
}
2012-05-27 12:23:30 +00:00
# endif
2012-05-27 12:12:29 +00:00
2012-07-24 00:47:28 +00:00
# ifdef HAVE_COMMAND
static void init_command ( void )
2012-05-27 12:12:29 +00:00
{
2012-07-24 00:47:28 +00:00
if ( ! g_settings . stdin_cmd_enable & & ! g_settings . network_cmd_enable )
2012-05-27 12:12:29 +00:00
return ;
2012-07-24 00:47:28 +00:00
if ( g_settings . stdin_cmd_enable & & driver . stdin_claimed )
{
2012-09-16 19:39:40 +00:00
RARCH_WARN ( " stdin command interface is desired, but input driver has already claimed stdin. \n "
2012-07-24 00:47:28 +00:00
" Cannot use this command interface. \n " ) ;
}
driver . command = rarch_cmd_new ( g_settings . stdin_cmd_enable & & ! driver . stdin_claimed ,
g_settings . network_cmd_enable , g_settings . network_cmd_port ) ;
if ( ! driver . command )
RARCH_ERR ( " Failed to initialize command interface. \n " ) ;
2012-05-27 12:12:29 +00:00
}
2012-07-24 00:47:28 +00:00
static void deinit_command ( void )
2012-05-27 12:12:29 +00:00
{
2012-07-24 00:47:28 +00:00
if ( driver . command )
2012-05-27 12:12:29 +00:00
{
2012-07-24 00:47:28 +00:00
rarch_cmd_free ( driver . command ) ;
driver . command = NULL ;
2012-05-27 12:12:29 +00:00
}
}
2011-03-19 19:41:07 +00:00
# endif
2011-02-13 15:40:24 +00:00
2012-04-07 10:20:37 +00:00
static void init_libretro_cbs_plain ( void )
2012-04-07 09:55:37 +00:00
{
pretro_set_video_refresh ( video_frame ) ;
pretro_set_audio_sample ( audio_sample ) ;
pretro_set_audio_sample_batch ( audio_sample_batch ) ;
pretro_set_input_state ( input_state ) ;
2013-03-16 09:35:22 +00:00
pretro_set_input_poll ( rarch_input_poll ) ;
2012-04-07 09:55:37 +00:00
}
2012-04-07 10:20:37 +00:00
static void init_libretro_cbs ( void )
2012-01-11 18:22:18 +00:00
{
2012-05-03 18:29:58 +00:00
init_libretro_cbs_plain ( ) ;
2012-01-11 18:22:18 +00:00
# ifdef HAVE_NETPLAY
if ( g_extern . netplay )
{
2012-04-07 09:55:37 +00:00
pretro_set_video_refresh ( g_extern . netplay_is_spectate ?
2012-01-11 18:22:18 +00:00
video_frame : video_frame_net ) ;
2012-04-07 09:55:37 +00:00
pretro_set_audio_sample ( g_extern . netplay_is_spectate ?
2012-01-11 18:22:18 +00:00
audio_sample : audio_sample_net ) ;
2012-04-07 09:55:37 +00:00
pretro_set_audio_sample_batch ( g_extern . netplay_is_spectate ?
audio_sample_batch : audio_sample_batch_net ) ;
2012-01-11 18:22:18 +00:00
2012-04-07 09:55:37 +00:00
pretro_set_input_state ( g_extern . netplay_is_spectate ?
2012-01-11 18:22:18 +00:00
( g_extern . netplay_is_client ? input_state_spectate_client : input_state_spectate )
: input_state_net ) ;
}
# endif
}
2013-11-08 00:54:46 +00:00
# if defined(HAVE_THREADS)
2013-04-29 13:56:49 +00:00
void rarch_init_autosave ( void )
2011-02-10 20:16:59 +00:00
{
2014-04-04 12:58:42 +00:00
if ( g_settings . autosave_interval < 1 | | ! g_extern . savefiles )
return ;
2011-02-11 12:44:31 +00:00
2014-04-04 12:58:42 +00:00
g_extern . autosave = ( autosave_t * * ) calloc ( g_extern . savefiles - > size , sizeof ( * g_extern . autosave ) ) ;
if ( ! g_extern . autosave )
return ;
2011-02-11 12:44:31 +00:00
2014-04-04 12:58:42 +00:00
g_extern . num_autosave = g_extern . savefiles - > size ;
2011-02-11 12:44:31 +00:00
2014-04-04 12:58:42 +00:00
unsigned i ;
for ( i = 0 ; i < g_extern . savefiles - > size ; i + + )
2011-02-10 20:16:59 +00:00
{
2014-04-04 12:58:42 +00:00
const char * path = g_extern . savefiles - > elems [ i ] . data ;
unsigned type = g_extern . savefiles - > elems [ i ] . attr . i ;
if ( pretro_get_memory_size ( type ) > 0 )
2011-02-11 12:44:31 +00:00
{
2014-04-12 11:25:48 +00:00
g_extern . autosave [ i ] = autosave_new ( path ,
pretro_get_memory_data ( type ) ,
pretro_get_memory_size ( type ) ,
2014-04-04 12:58:42 +00:00
g_settings . autosave_interval ) ;
if ( ! g_extern . autosave [ i ] )
RARCH_WARN ( " Could not initialize autosave. \n " ) ;
2011-02-11 12:44:31 +00:00
}
2011-02-10 20:16:59 +00:00
}
}
2013-04-29 13:56:49 +00:00
void rarch_deinit_autosave ( void )
2011-02-10 20:16:59 +00:00
{
2013-10-22 13:08:17 +00:00
unsigned i ;
2014-04-04 12:58:42 +00:00
for ( i = 0 ; i < g_extern . num_autosave ; i + + )
autosave_free ( g_extern . autosave [ i ] ) ;
free ( g_extern . autosave ) ;
2014-04-04 13:19:13 +00:00
g_extern . autosave = NULL ;
2014-04-04 12:58:42 +00:00
g_extern . num_autosave = 0 ;
2011-02-11 12:44:31 +00:00
}
2012-03-26 01:24:28 +00:00
# endif
2011-02-11 12:44:31 +00:00
2011-09-27 13:31:25 +00:00
static void set_savestate_auto_index ( void )
{
if ( ! g_settings . savestate_auto_index )
return ;
2012-06-23 13:31:22 +00:00
// Find the file in the same directory as g_extern.savestate_name with the largest numeral suffix.
// E.g. /foo/path/game.state, will try to find /foo/path/game.state%d, where %d is the largest number available.
2012-10-11 20:54:07 +00:00
char state_dir [ PATH_MAX ] ;
char state_base [ PATH_MAX ] ;
2011-09-27 13:31:25 +00:00
2012-10-11 20:54:07 +00:00
fill_pathname_basedir ( state_dir , g_extern . savestate_name , sizeof ( state_dir ) ) ;
fill_pathname_base ( state_base , g_extern . savestate_name , sizeof ( state_base ) ) ;
2011-09-27 13:31:25 +00:00
unsigned max_index = 0 ;
2012-10-11 20:54:07 +00:00
struct string_list * dir_list = dir_list_new ( state_dir , NULL , false ) ;
2011-09-27 13:31:25 +00:00
if ( ! dir_list )
return ;
2013-10-22 13:08:17 +00:00
size_t i ;
for ( i = 0 ; i < dir_list - > size ; i + + )
2011-09-27 13:31:25 +00:00
{
2012-06-23 13:31:22 +00:00
const char * dir_elem = dir_list - > elems [ i ] . data ;
2012-10-11 20:54:07 +00:00
char elem_base [ PATH_MAX ] ;
fill_pathname_base ( elem_base , dir_elem , sizeof ( elem_base ) ) ;
if ( strstr ( elem_base , state_base ) ! = elem_base )
2011-09-27 13:31:25 +00:00
continue ;
const char * end = dir_elem + strlen ( dir_elem ) ;
2012-06-23 13:31:22 +00:00
while ( ( end > dir_elem ) & & isdigit ( end [ - 1 ] ) ) end - - ;
2011-09-27 13:31:25 +00:00
unsigned index = strtoul ( end , NULL , 0 ) ;
if ( index > max_index )
max_index = index ;
}
dir_list_free ( dir_list ) ;
g_extern . state_slot = max_index ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Found last state slot: #%u \n " , g_extern . state_slot ) ;
2011-09-27 13:31:25 +00:00
}
2011-01-12 20:57:55 +00:00
static void fill_pathnames ( void )
{
2014-04-04 12:58:42 +00:00
string_list_free ( g_extern . savefiles ) ;
g_extern . savefiles = string_list_new ( ) ;
rarch_assert ( g_extern . savefiles ) ;
// For subsystems, we know exactly which RAM types are supported.
if ( * g_extern . subsystem )
2011-01-12 20:57:55 +00:00
{
2014-04-04 12:58:42 +00:00
unsigned i ;
2014-04-04 15:04:01 +00:00
const struct retro_subsystem_info * info = libretro_find_subsystem_info ( g_extern . system . special , g_extern . system . num_special , g_extern . subsystem ) ;
2012-01-06 19:32:30 +00:00
2014-04-04 12:58:42 +00:00
// We'll handle this error gracefully later.
2014-04-04 15:04:01 +00:00
unsigned num_roms = min ( info ? info - > num_roms : 0 , g_extern . subsystem_fullpaths ? g_extern . subsystem_fullpaths - > size : 0 ) ;
2014-04-04 12:58:42 +00:00
bool use_sram_dir = path_is_directory ( g_extern . savefile_name ) ;
2012-01-06 19:32:30 +00:00
2014-04-04 12:58:42 +00:00
for ( i = 0 ; i < num_roms ; i + + )
{
unsigned j ;
for ( j = 0 ; j < info - > roms [ i ] . num_memory ; j + + )
2012-01-06 19:32:30 +00:00
{
2014-04-04 15:04:01 +00:00
const struct retro_subsystem_memory_info * mem = & info - > roms [ i ] . memory [ j ] ;
2014-04-04 12:58:42 +00:00
union string_list_elem_attr attr ;
2012-01-06 19:32:30 +00:00
2014-04-04 12:58:42 +00:00
char path [ PATH_MAX ] ;
char ext [ 32 ] ;
2012-01-06 19:32:30 +00:00
2014-04-04 12:58:42 +00:00
snprintf ( ext , sizeof ( ext ) , " .%s " , mem - > extension ) ;
2012-01-06 19:32:30 +00:00
2014-04-04 12:58:42 +00:00
if ( use_sram_dir )
{
// Redirect ROM fullpath to save directory.
strlcpy ( path , g_extern . savefile_name , sizeof ( path ) ) ;
fill_pathname_dir ( path , g_extern . subsystem_fullpaths - > elems [ i ] . data , ext ,
sizeof ( path ) ) ;
}
else
{
fill_pathname ( path , g_extern . subsystem_fullpaths - > elems [ i ] . data ,
ext , sizeof ( path ) ) ;
}
2012-01-06 19:32:30 +00:00
2014-04-04 12:58:42 +00:00
attr . i = mem - > type ;
string_list_append ( g_extern . savefiles , path , attr ) ;
2012-01-06 19:32:30 +00:00
}
2014-04-04 12:58:42 +00:00
}
2012-01-06 19:32:30 +00:00
2014-04-04 12:58:42 +00:00
// Let other relevant paths be inferred from the main SRAM location.
if ( ! g_extern . has_set_save_path )
fill_pathname_noext ( g_extern . savefile_name , g_extern . basename , " .srm " , sizeof ( g_extern . savefile_name ) ) ;
if ( path_is_directory ( g_extern . savefile_name ) )
{
fill_pathname_dir ( g_extern . savefile_name , g_extern . basename , " .srm " , sizeof ( g_extern . savefile_name ) ) ;
RARCH_LOG ( " Redirecting save file to \" %s \" . \n " , g_extern . savefile_name ) ;
}
}
else
{
union string_list_elem_attr attr ;
attr . i = RETRO_MEMORY_SAVE_RAM ;
string_list_append ( g_extern . savefiles , g_extern . savefile_name , attr ) ;
2011-02-11 13:27:19 +00:00
2014-04-04 12:58:42 +00:00
// Infer .rtc save path from save ram path.
char savefile_name_rtc [ PATH_MAX ] ;
attr . i = RETRO_MEMORY_RTC ;
fill_pathname ( savefile_name_rtc ,
g_extern . savefile_name , " .rtc " , sizeof ( savefile_name_rtc ) ) ;
string_list_append ( g_extern . savefiles , savefile_name_rtc , attr ) ;
2011-01-12 20:57:55 +00:00
}
2011-02-11 13:27:19 +00:00
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2014-04-04 12:58:42 +00:00
fill_pathname ( g_extern . bsv . movie_path , g_extern . savefile_name , " " , sizeof ( g_extern . bsv . movie_path ) ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-03-23 22:31:33 +00:00
2011-08-17 22:05:56 +00:00
if ( * g_extern . basename )
{
2014-04-04 12:58:42 +00:00
if ( ! * g_extern . ups_name )
2011-08-17 22:05:56 +00:00
fill_pathname_noext ( g_extern . ups_name , g_extern . basename , " .ups " , sizeof ( g_extern . ups_name ) ) ;
2014-04-04 12:58:42 +00:00
if ( ! * g_extern . bps_name )
2011-08-17 22:05:56 +00:00
fill_pathname_noext ( g_extern . bps_name , g_extern . basename , " .bps " , sizeof ( g_extern . bps_name ) ) ;
2014-04-04 12:58:42 +00:00
if ( ! * g_extern . ips_name )
2012-03-20 22:08:34 +00:00
fill_pathname_noext ( g_extern . ips_name , g_extern . basename , " .ips " , sizeof ( g_extern . ips_name ) ) ;
2011-08-17 22:05:56 +00:00
}
2011-01-12 20:57:55 +00:00
}
2012-04-01 14:57:39 +00:00
static void load_auto_state ( void )
{
2012-05-03 22:45:53 +00:00
# ifdef HAVE_NETPLAY
if ( g_extern . netplay_enable & & ! g_extern . netplay_is_spectate )
return ;
# endif
2013-01-24 18:24:40 +00:00
if ( ! g_settings . savestate_auto_load )
return ;
2012-04-01 14:57:39 +00:00
char savestate_name_auto [ PATH_MAX ] ;
fill_pathname_noext ( savestate_name_auto , g_extern . savestate_name ,
" .auto " , sizeof ( savestate_name_auto ) ) ;
if ( path_file_exists ( savestate_name_auto ) )
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Found auto savestate in: %s \n " , savestate_name_auto ) ;
2012-06-02 20:32:27 +00:00
bool ret = load_state ( savestate_name_auto ) ;
2012-04-01 14:57:39 +00:00
char msg [ PATH_MAX ] ;
2012-06-02 20:32:27 +00:00
snprintf ( msg , sizeof ( msg ) , " Auto-loading savestate from \" %s \" %s. " , savestate_name_auto , ret ? " succeeded " : " failed " ) ;
2012-04-01 14:57:39 +00:00
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2012-06-02 20:32:27 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-04-01 14:57:39 +00:00
}
}
2012-06-02 19:33:37 +00:00
static void save_auto_state ( void )
{
if ( ! g_settings . savestate_auto_save )
return ;
char savestate_name_auto [ PATH_MAX ] ;
fill_pathname_noext ( savestate_name_auto , g_extern . savestate_name ,
" .auto " , sizeof ( savestate_name_auto ) ) ;
2012-06-02 20:32:27 +00:00
bool ret = save_state ( savestate_name_auto ) ;
RARCH_LOG ( " Auto save state to \" %s \" %s. \n " , savestate_name_auto , ret ? " succeeded " : " failed " ) ;
2012-06-02 19:33:37 +00:00
}
2012-04-21 21:25:32 +00:00
void rarch_load_state ( void )
2012-02-13 19:57:32 +00:00
{
char load_path [ PATH_MAX ] ;
if ( g_extern . state_slot > 0 )
2014-02-15 10:12:34 +00:00
snprintf ( load_path , sizeof ( load_path ) , " %s%d " , g_extern . savestate_name , g_extern . state_slot ) ;
else if ( g_extern . state_slot < 0 )
snprintf ( load_path , sizeof ( load_path ) , " %s.auto " , g_extern . savestate_name ) ;
2012-02-13 19:57:32 +00:00
else
snprintf ( load_path , sizeof ( load_path ) , " %s " , g_extern . savestate_name ) ;
2013-09-14 21:19:06 +00:00
size_t size = pretro_serialize_size ( ) ;
2012-02-13 19:57:32 +00:00
char msg [ 512 ] ;
2013-09-14 21:19:06 +00:00
if ( size )
{
if ( load_state ( load_path ) )
2014-02-15 10:12:34 +00:00
{
if ( g_extern . state_slot < 0 )
snprintf ( msg , sizeof ( msg ) , " Loaded state from slot #-1 (auto). " ) ;
else
snprintf ( msg , sizeof ( msg ) , " Loaded state from slot #%d. " , g_extern . state_slot ) ;
}
2013-09-14 21:19:06 +00:00
else
snprintf ( msg , sizeof ( msg ) , " Failed to load state from \" %s \" . " , load_path ) ;
}
2012-02-13 19:57:32 +00:00
else
2013-09-14 21:19:06 +00:00
strlcpy ( msg , " Core does not support save states. " , sizeof ( msg ) ) ;
2012-02-13 19:57:32 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 2 , 180 ) ;
2013-09-14 21:19:06 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-02-13 19:57:32 +00:00
}
2012-04-21 21:25:32 +00:00
void rarch_save_state ( void )
2012-02-13 19:57:32 +00:00
{
if ( g_settings . savestate_auto_index )
g_extern . state_slot + + ;
char save_path [ PATH_MAX ] ;
if ( g_extern . state_slot > 0 )
2014-02-15 10:12:34 +00:00
snprintf ( save_path , sizeof ( save_path ) , " %s%d " , g_extern . savestate_name , g_extern . state_slot ) ;
else if ( g_extern . state_slot < 0 )
snprintf ( save_path , sizeof ( save_path ) , " %s.auto " , g_extern . savestate_name ) ;
2012-02-13 19:57:32 +00:00
else
snprintf ( save_path , sizeof ( save_path ) , " %s " , g_extern . savestate_name ) ;
2013-09-14 21:19:06 +00:00
size_t size = pretro_serialize_size ( ) ;
2012-02-13 19:57:32 +00:00
char msg [ 512 ] ;
2013-09-14 21:19:06 +00:00
if ( size )
{
if ( save_state ( save_path ) )
2014-02-15 10:12:34 +00:00
{
if ( g_extern . state_slot < 0 )
snprintf ( msg , sizeof ( msg ) , " Saved state to slot #-1 (auto). " ) ;
else
snprintf ( msg , sizeof ( msg ) , " Saved state to slot #%u. " , g_extern . state_slot ) ;
}
2013-09-14 21:19:06 +00:00
else
snprintf ( msg , sizeof ( msg ) , " Failed to save state to \" %s \" . " , save_path ) ;
}
2012-02-13 19:57:32 +00:00
else
2013-09-14 21:19:06 +00:00
strlcpy ( msg , " Core does not support save states. " , sizeof ( msg ) ) ;
2012-02-13 19:57:32 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 2 , 180 ) ;
2013-09-14 21:19:06 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-02-13 19:57:32 +00:00
}
2011-01-23 22:09:54 +00:00
// Save or load state here.
2012-03-10 13:08:04 +00:00
static void check_savestates ( bool immutable )
2011-01-23 22:09:54 +00:00
{
static bool old_should_savestate = false ;
2012-04-21 21:25:32 +00:00
bool should_savestate = input_key_pressed_func ( RARCH_SAVE_STATE_KEY ) ;
2012-03-10 13:08:04 +00:00
2011-01-23 22:09:54 +00:00
if ( should_savestate & & ! old_should_savestate )
2012-04-21 21:25:32 +00:00
rarch_save_state ( ) ;
2011-01-23 22:09:54 +00:00
old_should_savestate = should_savestate ;
2012-03-10 13:08:04 +00:00
if ( ! immutable )
{
static bool old_should_loadstate = false ;
2012-04-21 21:25:32 +00:00
bool should_loadstate = input_key_pressed_func ( RARCH_LOAD_STATE_KEY ) ;
2012-03-10 13:08:04 +00:00
if ( ! should_savestate & & should_loadstate & & ! old_should_loadstate )
2012-04-21 21:25:32 +00:00
rarch_load_state ( ) ;
2012-03-10 13:08:04 +00:00
old_should_loadstate = should_loadstate ;
}
2011-01-23 22:09:54 +00:00
}
2013-04-20 22:01:49 +00:00
void rarch_set_fullscreen ( bool fullscreen )
{
g_settings . video . fullscreen = fullscreen ;
2013-07-05 16:53:42 +00:00
driver . video_cache_context = g_extern . system . hw_render_callback . cache_context ;
2013-06-23 21:01:34 +00:00
driver . video_cache_context_ack = false ;
2013-04-20 22:01:49 +00:00
uninit_drivers ( ) ;
init_drivers ( ) ;
2013-06-23 21:01:34 +00:00
driver . video_cache_context = false ;
2013-04-20 22:01:49 +00:00
// Poll input to avoid possibly stale data to corrupt things.
if ( driver . input )
input_poll_func ( ) ;
}
2014-02-08 15:27:09 +00:00
bool rarch_check_fullscreen ( void )
2011-01-23 22:09:54 +00:00
{
// If we go fullscreen we drop all drivers and reinit to be safe.
2011-10-18 12:39:54 +00:00
static bool was_pressed = false ;
2012-04-21 21:25:32 +00:00
bool pressed = input_key_pressed_func ( RARCH_FULLSCREEN_TOGGLE_KEY ) ;
2011-10-18 12:39:54 +00:00
bool toggle = pressed & & ! was_pressed ;
2013-11-11 11:35:20 +00:00
2011-10-18 12:39:54 +00:00
if ( toggle )
2011-01-23 22:09:54 +00:00
{
2013-11-11 11:35:20 +00:00
g_settings . video . fullscreen = ! g_settings . video . fullscreen ;
2013-04-20 22:01:49 +00:00
rarch_set_fullscreen ( g_settings . video . fullscreen ) ;
2011-01-23 22:09:54 +00:00
}
2011-04-09 11:15:14 +00:00
was_pressed = pressed ;
2011-10-18 12:39:54 +00:00
return toggle ;
2011-01-23 22:09:54 +00:00
}
2012-04-21 21:25:32 +00:00
void rarch_state_slot_increase ( void )
2012-02-15 17:49:23 +00:00
{
g_extern . state_slot + + ;
if ( g_extern . msg_queue )
msg_queue_clear ( g_extern . msg_queue ) ;
char msg [ 256 ] ;
2013-11-12 09:25:38 +00:00
snprintf ( msg , sizeof ( msg ) , " State slot: %u " , g_extern . state_slot ) ;
2012-02-15 17:49:23 +00:00
if ( g_extern . msg_queue )
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-02-15 17:49:23 +00:00
}
2012-04-21 21:25:32 +00:00
void rarch_state_slot_decrease ( void )
2012-02-15 17:49:23 +00:00
{
if ( g_extern . state_slot > 0 )
g_extern . state_slot - - ;
if ( g_extern . msg_queue )
msg_queue_clear ( g_extern . msg_queue ) ;
char msg [ 256 ] ;
2013-11-12 09:25:38 +00:00
snprintf ( msg , sizeof ( msg ) , " State slot: %u " , g_extern . state_slot ) ;
2012-02-15 17:49:23 +00:00
if ( g_extern . msg_queue )
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-02-15 17:49:23 +00:00
}
2011-01-23 22:09:54 +00:00
static void check_stateslots ( void )
{
// Save state slots
static bool old_should_slot_increase = false ;
2012-04-21 21:25:32 +00:00
bool should_slot_increase = input_key_pressed_func ( RARCH_STATE_SLOT_PLUS ) ;
2011-01-23 22:09:54 +00:00
if ( should_slot_increase & & ! old_should_slot_increase )
2012-04-21 21:25:32 +00:00
rarch_state_slot_increase ( ) ;
2011-01-23 22:09:54 +00:00
old_should_slot_increase = should_slot_increase ;
static bool old_should_slot_decrease = false ;
2012-04-21 21:25:32 +00:00
bool should_slot_decrease = input_key_pressed_func ( RARCH_STATE_SLOT_MINUS ) ;
2011-01-23 22:09:54 +00:00
if ( should_slot_decrease & & ! old_should_slot_decrease )
2012-04-21 21:25:32 +00:00
rarch_state_slot_decrease ( ) ;
2011-01-23 22:09:54 +00:00
old_should_slot_decrease = should_slot_decrease ;
}
2011-10-15 12:33:41 +00:00
static inline void flush_rewind_audio ( void )
{
2011-11-20 01:06:25 +00:00
if ( g_extern . frame_is_reverse ) // We just rewound. Flush rewind audio buffer.
2011-10-15 12:33:41 +00:00
{
g_extern . audio_active = audio_flush ( g_extern . audio_data . rewind_buf + g_extern . audio_data . rewind_ptr ,
2011-11-20 01:06:25 +00:00
g_extern . audio_data . rewind_size - g_extern . audio_data . rewind_ptr ) & & g_extern . audio_active ;
2011-10-15 12:33:41 +00:00
}
}
static inline void setup_rewind_audio ( void )
{
2013-10-22 13:08:17 +00:00
unsigned i ;
2011-10-15 12:33:41 +00:00
// Push audio ready to be played.
g_extern . audio_data . rewind_ptr = g_extern . audio_data . rewind_size ;
2013-10-22 13:08:17 +00:00
for ( i = 0 ; i < g_extern . audio_data . data_ptr ; i + = 2 )
2011-10-15 12:33:41 +00:00
{
g_extern . audio_data . rewind_buf [ - - g_extern . audio_data . rewind_ptr ] =
g_extern . audio_data . conv_outsamples [ i + 1 ] ;
g_extern . audio_data . rewind_buf [ - - g_extern . audio_data . rewind_ptr ] =
g_extern . audio_data . conv_outsamples [ i + 0 ] ;
}
g_extern . audio_data . data_ptr = 0 ;
}
2011-01-31 15:48:42 +00:00
static void check_rewind ( void )
{
2011-10-15 12:33:41 +00:00
flush_rewind_audio ( ) ;
2011-01-31 16:24:31 +00:00
g_extern . frame_is_reverse = false ;
2011-10-15 12:33:41 +00:00
2011-02-25 23:31:13 +00:00
static bool first = true ;
if ( first )
{
first = false ;
return ;
}
2011-01-31 15:48:42 +00:00
if ( ! g_extern . state_manager )
return ;
2012-04-21 21:25:32 +00:00
if ( input_key_pressed_func ( RARCH_REWIND ) )
2011-01-31 15:48:42 +00:00
{
2011-01-31 17:49:50 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
2014-02-21 20:51:58 +00:00
const void * buf ;
2011-01-31 15:48:42 +00:00
if ( state_manager_pop ( g_extern . state_manager , & buf ) )
2011-01-31 16:24:31 +00:00
{
2011-02-25 23:31:13 +00:00
g_extern . frame_is_reverse = true ;
2011-10-15 12:33:41 +00:00
setup_rewind_audio ( ) ;
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Rewinding. " , 0 , g_extern . is_paused ? 1 : 30 ) ;
2012-04-07 09:55:37 +00:00
pretro_unserialize ( buf , g_extern . state_size ) ;
2011-02-25 23:31:13 +00:00
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-11-20 19:19:05 +00:00
if ( g_extern . bsv . movie )
bsv_movie_frame_rewind ( g_extern . bsv . movie ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-01-31 16:24:31 +00:00
}
2011-01-31 17:49:50 +00:00
else
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Reached end of rewind buffer. " , 0 , 30 ) ;
2011-01-31 15:48:42 +00:00
}
else
{
2011-02-01 16:30:18 +00:00
static unsigned cnt = 0 ;
cnt = ( cnt + 1 ) % ( g_settings . rewind_granularity ? g_settings . rewind_granularity : 1 ) ; // Avoid possible SIGFPE.
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-11-20 19:19:05 +00:00
if ( cnt = = 0 | | g_extern . bsv . movie )
2012-03-25 22:04:12 +00:00
# else
if ( cnt = = 0 )
# endif
2011-02-01 16:30:18 +00:00
{
2014-02-21 20:42:05 +00:00
void * state ;
state_manager_push_where ( g_extern . state_manager , & state ) ;
2014-02-23 10:10:25 +00:00
2014-02-22 12:13:18 +00:00
RARCH_PERFORMANCE_INIT ( rewind_serialize ) ;
RARCH_PERFORMANCE_START ( rewind_serialize ) ;
2014-02-18 07:41:52 +00:00
pretro_serialize ( state , g_extern . state_size ) ;
2014-02-22 12:13:18 +00:00
RARCH_PERFORMANCE_STOP ( rewind_serialize ) ;
2014-02-23 10:10:25 +00:00
2014-02-18 07:41:52 +00:00
state_manager_push_do ( g_extern . state_manager ) ;
2011-02-01 16:30:18 +00:00
}
2011-01-31 15:48:42 +00:00
}
2011-10-15 12:33:41 +00:00
2012-04-07 09:55:37 +00:00
pretro_set_audio_sample ( g_extern . frame_is_reverse ?
audio_sample_rewind : audio_sample ) ;
pretro_set_audio_sample_batch ( g_extern . frame_is_reverse ?
audio_sample_batch_rewind : audio_sample_batch ) ;
2011-01-31 15:48:42 +00:00
}
2012-03-04 11:01:07 +00:00
static void check_slowmotion ( void )
{
2012-04-21 21:25:32 +00:00
g_extern . is_slowmotion = input_key_pressed_func ( RARCH_SLOWMOTION ) ;
2012-03-04 11:01:07 +00:00
if ( g_extern . is_slowmotion )
{
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , g_extern . frame_is_reverse ? " Slow motion rewind. " : " Slow motion. " , 0 , 30 ) ;
}
}
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2012-03-10 17:31:25 +00:00
static void movie_record_toggle ( void )
2011-02-02 11:45:56 +00:00
{
2012-03-10 17:31:25 +00:00
if ( g_extern . bsv . movie )
2011-02-02 11:45:56 +00:00
{
2012-03-10 17:31:25 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , " Stopping movie record. " , 2 , 180 ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Stopping movie record. \n " ) ;
2012-03-10 17:31:25 +00:00
bsv_movie_free ( g_extern . bsv . movie ) ;
g_extern . bsv . movie = NULL ;
}
else
{
g_settings . rewind_granularity = 1 ;
char path [ PATH_MAX ] ;
if ( g_extern . state_slot > 0 )
2011-02-02 11:45:56 +00:00
{
2012-03-10 17:31:25 +00:00
snprintf ( path , sizeof ( path ) , " %s%u.bsv " ,
g_extern . bsv . movie_path , g_extern . state_slot ) ;
2011-02-02 11:45:56 +00:00
}
else
{
2012-03-10 17:31:25 +00:00
snprintf ( path , sizeof ( path ) , " %s.bsv " ,
g_extern . bsv . movie_path ) ;
}
2011-02-02 12:37:01 +00:00
2012-03-10 17:31:25 +00:00
char msg [ PATH_MAX ] ;
snprintf ( msg , sizeof ( msg ) , " Starting movie record to \" %s \" . " , path ) ;
2011-11-19 00:33:21 +00:00
2012-04-21 21:25:32 +00:00
g_extern . bsv . movie = bsv_movie_init ( path , RARCH_MOVIE_RECORD ) ;
2012-03-10 17:31:25 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , g_extern . bsv . movie ? msg : " Failed to start movie record. " , 1 , 180 ) ;
2011-02-02 11:45:56 +00:00
2012-03-10 17:31:25 +00:00
if ( g_extern . bsv . movie )
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Starting movie record to \" %s \" . \n " , path ) ;
2012-03-10 17:31:25 +00:00
else
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to start movie record. \n " ) ;
2011-02-02 11:45:56 +00:00
}
2012-03-10 17:31:25 +00:00
}
2011-02-02 11:45:56 +00:00
2012-03-10 17:31:25 +00:00
static void check_movie_record ( bool pressed )
{
if ( pressed )
movie_record_toggle ( ) ;
2011-02-02 11:45:56 +00:00
}
2012-03-10 17:31:25 +00:00
static void check_movie_playback ( bool pressed )
2011-11-20 02:00:21 +00:00
{
2012-03-10 17:31:25 +00:00
if ( g_extern . bsv . movie_end | | pressed )
2011-11-20 02:00:21 +00:00
{
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Movie playback ended. " , 1 , 180 ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Movie playback ended. \n " ) ;
2011-11-20 19:19:05 +00:00
bsv_movie_free ( g_extern . bsv . movie ) ;
g_extern . bsv . movie = NULL ;
g_extern . bsv . movie_end = false ;
g_extern . bsv . movie_playback = false ;
2011-11-20 02:00:21 +00:00
}
}
2012-03-10 17:31:25 +00:00
static void check_movie ( void )
{
static bool old_button = false ;
2012-04-21 21:25:32 +00:00
bool new_button = input_key_pressed_func ( RARCH_MOVIE_RECORD_TOGGLE ) ;
2012-03-10 17:31:25 +00:00
bool pressed = new_button & & ! old_button ;
if ( g_extern . bsv . movie_playback )
check_movie_playback ( pressed ) ;
else
check_movie_record ( pressed ) ;
old_button = new_button ;
}
2012-03-25 22:04:12 +00:00
# endif
2012-03-10 17:31:25 +00:00
2011-02-05 19:46:58 +00:00
static void check_pause ( void )
{
static bool old_state = false ;
2012-04-21 21:25:32 +00:00
bool new_state = input_key_pressed_func ( RARCH_PAUSE_TOGGLE ) ;
2011-02-05 20:45:44 +00:00
2011-10-18 19:57:28 +00:00
// FRAMEADVANCE will set us into pause mode.
2012-04-21 21:25:32 +00:00
new_state | = ! g_extern . is_paused & & input_key_pressed_func ( RARCH_FRAMEADVANCE ) ;
2011-10-18 19:57:28 +00:00
2011-02-05 20:45:44 +00:00
static bool old_focus = true ;
bool focus = true ;
if ( g_settings . pause_nonactive )
2012-03-28 22:30:50 +00:00
focus = video_focus_func ( ) ;
2011-02-05 20:45:44 +00:00
if ( focus & & new_state & & ! old_state )
2011-02-05 19:46:58 +00:00
{
g_extern . is_paused = ! g_extern . is_paused ;
if ( g_extern . is_paused )
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Paused. \n " ) ;
2011-02-05 19:46:58 +00:00
if ( driver . audio_data )
2012-03-28 22:30:50 +00:00
audio_stop_func ( ) ;
2011-02-05 19:46:58 +00:00
}
2014-04-12 11:25:48 +00:00
else
2011-02-05 19:46:58 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Unpaused. \n " ) ;
2011-02-05 19:46:58 +00:00
if ( driver . audio_data )
2011-02-06 22:55:17 +00:00
{
2013-08-04 12:57:31 +00:00
if ( ! g_extern . audio_data . mute & & ! audio_start_func ( ) )
2011-02-06 22:55:17 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to resume audio driver. Will continue without audio. \n " ) ;
2011-02-06 22:55:17 +00:00
g_extern . audio_active = false ;
}
}
2011-02-05 19:46:58 +00:00
}
}
2011-02-05 20:45:44 +00:00
else if ( focus & & ! old_focus )
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Unpaused. \n " ) ;
2011-02-05 20:45:44 +00:00
g_extern . is_paused = false ;
2013-08-04 12:57:31 +00:00
if ( driver . audio_data & & ! g_extern . audio_data . mute & & ! audio_start_func ( ) )
2011-02-06 22:55:17 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to resume audio driver. Will continue without audio. \n " ) ;
2012-03-28 22:30:50 +00:00
g_extern . audio_active = false ;
2011-02-06 22:55:17 +00:00
}
2011-02-05 20:45:44 +00:00
}
else if ( ! focus & & old_focus )
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Paused. \n " ) ;
2011-02-05 20:45:44 +00:00
g_extern . is_paused = true ;
if ( driver . audio_data )
2012-03-28 22:30:50 +00:00
audio_stop_func ( ) ;
2011-02-05 20:45:44 +00:00
}
2011-02-05 19:46:58 +00:00
2011-02-05 20:45:44 +00:00
old_focus = focus ;
2011-02-05 19:46:58 +00:00
old_state = new_state ;
}
2011-10-17 19:30:58 +00:00
static void check_oneshot ( void )
{
static bool old_state = false ;
2012-04-21 21:25:32 +00:00
bool new_state = input_key_pressed_func ( RARCH_FRAMEADVANCE ) ;
2011-10-18 19:57:28 +00:00
g_extern . is_oneshot = ( new_state & & ! old_state ) ;
2011-10-17 19:30:58 +00:00
old_state = new_state ;
2011-10-18 19:57:28 +00:00
// Rewind buttons works like FRAMEREWIND when paused. We will one-shot in that case.
static bool old_rewind_state = false ;
2012-04-21 21:25:32 +00:00
bool new_rewind_state = input_key_pressed_func ( RARCH_REWIND ) ;
2011-10-18 19:57:28 +00:00
g_extern . is_oneshot | = new_rewind_state & & ! old_rewind_state ;
old_rewind_state = new_rewind_state ;
2011-10-17 19:30:58 +00:00
}
2012-04-21 21:25:32 +00:00
void rarch_game_reset ( void )
2012-02-02 13:22:43 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Resetting game. \n " ) ;
2012-02-02 13:22:43 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Reset. " , 1 , 120 ) ;
2012-04-07 09:55:37 +00:00
pretro_reset ( ) ;
2012-02-02 13:22:43 +00:00
init_controllers ( ) ; // bSNES since v073r01 resets controllers to JOYPAD after a reset, so just enforce it here.
}
2011-03-24 19:41:28 +00:00
static void check_reset ( void )
{
2011-10-29 11:35:01 +00:00
static bool old_state = false ;
2012-04-21 21:25:32 +00:00
bool new_state = input_key_pressed_func ( RARCH_RESET ) ;
2011-10-29 11:35:01 +00:00
if ( new_state & & ! old_state )
2012-04-21 21:25:32 +00:00
rarch_game_reset ( ) ;
2011-10-29 11:35:01 +00:00
old_state = new_state ;
2011-03-24 19:41:28 +00:00
}
2012-10-01 20:15:48 +00:00
static void check_turbo ( void )
{
2013-10-22 13:08:17 +00:00
unsigned i ;
2012-10-01 20:15:48 +00:00
g_extern . turbo_count + + ;
static const struct retro_keybind * binds [ MAX_PLAYERS ] = {
g_settings . input . binds [ 0 ] ,
g_settings . input . binds [ 1 ] ,
g_settings . input . binds [ 2 ] ,
g_settings . input . binds [ 3 ] ,
g_settings . input . binds [ 4 ] ,
g_settings . input . binds [ 5 ] ,
g_settings . input . binds [ 6 ] ,
g_settings . input . binds [ 7 ] ,
} ;
2013-10-22 13:08:17 +00:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2012-10-01 20:15:48 +00:00
g_extern . turbo_frame_enable [ i ] =
input_input_state_func ( binds , i , RETRO_DEVICE_JOYPAD , 0 , RARCH_TURBO_ENABLE ) ;
}
2011-03-29 16:28:31 +00:00
static void check_shader_dir ( void )
{
2012-12-22 14:33:28 +00:00
static bool old_pressed_next ;
static bool old_pressed_prev ;
2011-03-29 16:28:31 +00:00
2012-09-21 19:20:30 +00:00
if ( ! g_extern . shader_dir . list | | ! driver . video - > set_shader )
2011-03-29 16:28:31 +00:00
return ;
bool should_apply = false ;
2012-04-21 21:25:32 +00:00
bool pressed_next = input_key_pressed_func ( RARCH_SHADER_NEXT ) ;
bool pressed_prev = input_key_pressed_func ( RARCH_SHADER_PREV ) ;
2011-03-29 16:28:31 +00:00
if ( pressed_next & & ! old_pressed_next )
{
should_apply = true ;
2012-06-23 13:31:22 +00:00
g_extern . shader_dir . ptr = ( g_extern . shader_dir . ptr + 1 ) % g_extern . shader_dir . list - > size ;
2011-03-29 16:28:31 +00:00
}
else if ( pressed_prev & & ! old_pressed_prev )
{
should_apply = true ;
if ( g_extern . shader_dir . ptr = = 0 )
2012-06-23 13:31:22 +00:00
g_extern . shader_dir . ptr = g_extern . shader_dir . list - > size - 1 ;
2011-03-29 16:28:31 +00:00
else
g_extern . shader_dir . ptr - - ;
}
if ( should_apply )
{
2012-09-21 19:20:30 +00:00
const char * shader = g_extern . shader_dir . list - > elems [ g_extern . shader_dir . ptr ] . data ;
enum rarch_shader_type type = RARCH_SHADER_NONE ;
2011-03-29 17:09:10 +00:00
2012-09-21 19:20:30 +00:00
const char * ext = strrchr ( shader , ' . ' ) ;
if ( ext )
{
if ( strcmp ( ext , " .shader " ) = = 0 )
2013-01-07 16:03:10 +00:00
type = RARCH_SHADER_GLSL ;
2012-09-21 19:20:30 +00:00
else if ( strcmp ( ext , " .cg " ) = = 0 | | strcmp ( ext , " .cgp " ) = = 0 )
type = RARCH_SHADER_CG ;
}
if ( type = = RARCH_SHADER_NONE )
return ;
2011-03-29 17:09:10 +00:00
2011-03-29 16:28:31 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
2012-09-21 19:20:30 +00:00
2011-03-29 16:28:31 +00:00
char msg [ 512 ] ;
2012-09-21 19:56:54 +00:00
snprintf ( msg , sizeof ( msg ) , " Shader #%u: \" %s \" . " , ( unsigned ) g_extern . shader_dir . ptr , shader ) ;
2011-03-29 16:28:31 +00:00
msg_queue_push ( g_extern . msg_queue , msg , 1 , 120 ) ;
2012-09-21 19:56:54 +00:00
RARCH_LOG ( " Applying shader \" %s \" . \n " , shader ) ;
2011-03-29 16:28:31 +00:00
2013-04-07 11:00:21 +00:00
if ( ! video_set_shader_func ( type , shader ) )
2012-04-21 21:25:32 +00:00
RARCH_WARN ( " Failed to apply shader. \n " ) ;
2011-03-29 16:28:31 +00:00
}
old_pressed_next = pressed_next ;
old_pressed_prev = pressed_prev ;
}
2011-04-17 14:53:19 +00:00
static void check_cheats ( void )
{
if ( ! g_extern . cheat )
return ;
2012-12-22 14:33:28 +00:00
static bool old_pressed_prev ;
static bool old_pressed_next ;
static bool old_pressed_toggle ;
2011-04-17 14:53:19 +00:00
2012-04-21 21:25:32 +00:00
bool pressed_next = input_key_pressed_func ( RARCH_CHEAT_INDEX_PLUS ) ;
bool pressed_prev = input_key_pressed_func ( RARCH_CHEAT_INDEX_MINUS ) ;
bool pressed_toggle = input_key_pressed_func ( RARCH_CHEAT_TOGGLE ) ;
2011-04-17 14:53:19 +00:00
if ( pressed_next & & ! old_pressed_next )
cheat_manager_index_next ( g_extern . cheat ) ;
else if ( pressed_prev & & ! old_pressed_prev )
cheat_manager_index_prev ( g_extern . cheat ) ;
else if ( pressed_toggle & & ! old_pressed_toggle )
cheat_manager_toggle ( g_extern . cheat ) ;
old_pressed_prev = pressed_prev ;
old_pressed_next = pressed_next ;
old_pressed_toggle = pressed_toggle ;
}
2011-03-29 16:28:31 +00:00
2013-04-27 13:14:59 +00:00
void rarch_disk_control_append_image ( const char * path )
{
const struct retro_disk_control_callback * control = & g_extern . system . disk_control ;
rarch_disk_control_set_eject ( true , false ) ;
control - > add_image_index ( ) ;
unsigned new_index = control - > get_num_images ( ) ;
if ( ! new_index )
return ;
new_index - - ;
struct retro_game_info info = { 0 } ;
info . path = path ;
control - > replace_image_index ( new_index , & info ) ;
rarch_disk_control_set_index ( new_index ) ;
char msg [ 512 ] ;
snprintf ( msg , sizeof ( msg ) , " Appended disk: %s " , path ) ;
RARCH_LOG ( " %s \n " , msg ) ;
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 0 , 180 ) ;
2013-11-08 00:54:46 +00:00
# if defined(HAVE_THREADS)
2013-04-29 13:56:49 +00:00
rarch_deinit_autosave ( ) ;
2013-04-27 13:14:59 +00:00
# endif
2014-04-04 12:58:42 +00:00
// TODO: Need to figure out what to do with subsystems case.
if ( ! * g_extern . subsystem )
{
// Update paths for our new image.
// If we actually use append_image,
// we assume that we started out in a single disk case,
// and that this way of doing it makes the most sense.
set_paths ( path ) ;
fill_pathnames ( ) ;
}
2013-04-27 13:14:59 +00:00
2013-11-08 00:54:46 +00:00
# if defined(HAVE_THREADS)
2013-04-29 13:56:49 +00:00
rarch_init_autosave ( ) ;
2013-04-27 13:14:59 +00:00
# endif
rarch_disk_control_set_eject ( false , false ) ;
}
2013-04-27 10:01:34 +00:00
void rarch_disk_control_set_eject ( bool new_state , bool log )
2013-02-21 22:44:07 +00:00
{
const struct retro_disk_control_callback * control = & g_extern . system . disk_control ;
if ( ! control - > get_num_images )
return ;
bool error = false ;
char msg [ 256 ] ;
* msg = ' \0 ' ;
2013-04-27 10:01:34 +00:00
if ( control - > set_eject_state ( new_state ) )
snprintf ( msg , sizeof ( msg ) , " %s virtual disk tray. " , new_state ? " Ejected " : " Closed " ) ;
else
2013-02-21 22:44:07 +00:00
{
2013-04-27 10:01:34 +00:00
error = true ;
snprintf ( msg , sizeof ( msg ) , " Failed to %s virtual disk tray. " , new_state ? " eject " : " close " ) ;
}
if ( * msg )
{
if ( error )
RARCH_ERR ( " %s \n " , msg ) ;
2013-02-21 22:44:07 +00:00
else
2013-04-27 10:01:34 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
// Only noise in RGUI.
if ( log )
2013-02-21 22:44:07 +00:00
{
2013-04-27 10:01:34 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2013-02-21 22:44:07 +00:00
}
}
2013-04-27 10:01:34 +00:00
}
void rarch_disk_control_set_index ( unsigned next_index )
{
const struct retro_disk_control_callback * control = & g_extern . system . disk_control ;
if ( ! control - > get_num_images )
return ;
bool error = false ;
char msg [ 256 ] ;
* msg = ' \0 ' ;
unsigned num_disks = control - > get_num_images ( ) ;
if ( control - > set_image_index ( next_index ) )
2013-02-21 22:44:07 +00:00
{
2013-04-27 10:01:34 +00:00
if ( next_index < num_disks )
snprintf ( msg , sizeof ( msg ) , " Setting disk %u of %u in tray. " , next_index + 1 , num_disks ) ;
2013-02-21 22:44:07 +00:00
else
2013-11-12 09:25:38 +00:00
strlcpy ( msg , " Removed disk from tray. " , sizeof ( msg ) ) ;
2013-04-27 10:01:34 +00:00
}
else
{
if ( next_index < num_disks )
snprintf ( msg , sizeof ( msg ) , " Failed to set disk %u of %u. " , next_index + 1 , num_disks ) ;
else
2013-11-12 09:25:38 +00:00
strlcpy ( msg , " Failed to remove disk from tray. " , sizeof ( msg ) ) ;
2013-04-27 10:01:34 +00:00
error = true ;
2013-02-21 22:44:07 +00:00
}
if ( * msg )
{
if ( error )
RARCH_ERR ( " %s \n " , msg ) ;
else
RARCH_LOG ( " %s \n " , msg ) ;
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
}
2013-04-27 10:01:34 +00:00
}
static void check_disk ( void )
{
const struct retro_disk_control_callback * control = & g_extern . system . disk_control ;
if ( ! control - > get_num_images )
return ;
static bool old_pressed_eject ;
static bool old_pressed_next ;
bool pressed_eject = input_key_pressed_func ( RARCH_DISK_EJECT_TOGGLE ) ;
bool pressed_next = input_key_pressed_func ( RARCH_DISK_NEXT ) ;
if ( pressed_eject & & ! old_pressed_eject )
{
bool new_state = ! control - > get_eject_state ( ) ;
rarch_disk_control_set_eject ( new_state , true ) ;
}
else if ( pressed_next & & ! old_pressed_next )
{
unsigned num_disks = control - > get_num_images ( ) ;
unsigned current = control - > get_image_index ( ) ;
if ( num_disks & & num_disks ! = UINT_MAX )
{
// Use "no disk" state when index == num_disks.
unsigned next_index = current > = num_disks ? 0 : ( ( current + 1 ) % ( num_disks + 1 ) ) ;
rarch_disk_control_set_index ( next_index ) ;
}
else
RARCH_ERR ( " Got invalid disk index from libretro. \n " ) ;
}
2013-02-21 22:44:07 +00:00
old_pressed_eject = pressed_eject ;
old_pressed_next = pressed_next ;
}
2012-08-20 01:30:09 +00:00
# if defined(HAVE_SCREENSHOTS) && !defined(_XBOX)
2011-05-15 15:16:29 +00:00
static void check_screenshot ( void )
{
2012-12-22 14:33:28 +00:00
static bool old_pressed ;
2012-04-21 21:25:32 +00:00
bool pressed = input_key_pressed_func ( RARCH_SCREENSHOT ) ;
2011-10-23 10:38:11 +00:00
if ( pressed & & ! old_pressed )
2013-06-16 11:44:07 +00:00
rarch_take_screenshot ( ) ;
2011-10-23 10:38:11 +00:00
2011-05-15 15:16:29 +00:00
old_pressed = pressed ;
}
2012-01-26 02:00:56 +00:00
# endif
2011-05-15 15:16:29 +00:00
2011-05-17 17:20:41 +00:00
# ifdef HAVE_DYLIB
static void check_dsp_config ( void )
{
if ( ! g_extern . audio_data . dsp_plugin | | ! g_extern . audio_data . dsp_plugin - > config )
return ;
2012-12-22 14:33:28 +00:00
static bool old_pressed ;
2012-04-21 21:25:32 +00:00
bool pressed = input_key_pressed_func ( RARCH_DSP_CONFIG ) ;
2011-05-17 17:20:41 +00:00
if ( pressed & & ! old_pressed )
g_extern . audio_data . dsp_plugin - > config ( g_extern . audio_data . dsp_handle ) ;
old_pressed = pressed ;
}
# endif
2011-11-26 14:54:58 +00:00
static void check_mute ( void )
{
if ( ! g_extern . audio_active )
return ;
2012-12-22 14:33:28 +00:00
static bool old_pressed ;
2012-04-21 21:25:32 +00:00
bool pressed = input_key_pressed_func ( RARCH_MUTE ) ;
2011-11-26 14:54:58 +00:00
if ( pressed & & ! old_pressed )
{
g_extern . audio_data . mute = ! g_extern . audio_data . mute ;
2012-02-11 19:59:41 +00:00
const char * msg = g_extern . audio_data . mute ? " Audio muted. " : " Audio unmuted. " ;
2011-11-26 14:54:58 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2013-08-04 12:57:31 +00:00
if ( driver . audio_data )
{
if ( g_extern . audio_data . mute )
audio_stop_func ( ) ;
else if ( ! audio_start_func ( ) )
{
RARCH_ERR ( " Failed to unmute audio. \n " ) ;
g_extern . audio_active = false ;
}
}
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2011-11-26 14:54:58 +00:00
}
old_pressed = pressed ;
}
2012-11-03 13:15:03 +00:00
static void check_volume ( void )
{
if ( ! g_extern . audio_active )
return ;
float db_change = 0.0f ;
bool pressed_up = input_key_pressed_func ( RARCH_VOLUME_UP ) ;
bool pressed_down = input_key_pressed_func ( RARCH_VOLUME_DOWN ) ;
if ( ! pressed_up & & ! pressed_down )
return ;
if ( pressed_up )
db_change + = 0.5f ;
if ( pressed_down )
db_change - = 0.5f ;
g_extern . audio_data . volume_db + = db_change ;
2013-12-29 11:01:23 +00:00
g_extern . audio_data . volume_db = max ( g_extern . audio_data . volume_db , - 80.0f ) ;
g_extern . audio_data . volume_db = min ( g_extern . audio_data . volume_db , 12.0f ) ;
2012-11-03 13:15:03 +00:00
char msg [ 256 ] ;
snprintf ( msg , sizeof ( msg ) , " Volume: %.1f dB " , g_extern . audio_data . volume_db ) ;
msg_queue_clear ( g_extern . msg_queue ) ;
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
RARCH_LOG ( " %s \n " , msg ) ;
g_extern . audio_data . volume_gain = db_to_gain ( g_extern . audio_data . volume_db ) ;
}
2011-11-26 14:54:58 +00:00
2012-01-21 13:24:38 +00:00
# ifdef HAVE_NETPLAY
static void check_netplay_flip ( void )
{
2012-12-22 14:33:28 +00:00
static bool old_pressed ;
2012-04-21 21:25:32 +00:00
bool pressed = input_key_pressed_func ( RARCH_NETPLAY_FLIP ) ;
2012-01-21 13:24:38 +00:00
if ( pressed & & ! old_pressed )
netplay_flip_players ( g_extern . netplay ) ;
old_pressed = pressed ;
}
# endif
2013-12-09 15:18:58 +00:00
void rarch_check_block_hotkey ( void )
2012-11-02 22:24:53 +00:00
{
2013-12-09 15:18:58 +00:00
driver . block_hotkey = driver . block_input ;
2012-11-02 22:24:53 +00:00
2014-04-12 11:25:48 +00:00
// If we haven't bound anything to this,
2012-11-02 22:24:53 +00:00
// always allow hotkeys.
static const struct retro_keybind * bind = & g_settings . input . binds [ 0 ] [ RARCH_ENABLE_HOTKEY ] ;
2013-12-09 15:18:58 +00:00
if ( ! driver . block_hotkey & & bind - > key = = RETROK_UNKNOWN & & bind - > joykey = = NO_BTN & & bind - > joyaxis = = AXIS_NONE )
2012-11-02 22:24:53 +00:00
return ;
2013-12-09 15:18:58 +00:00
driver . block_hotkey = driver . block_input | | ! input_key_pressed_func ( RARCH_ENABLE_HOTKEY ) ;
2012-11-02 22:24:53 +00:00
}
2012-12-23 17:36:58 +00:00
# ifdef HAVE_OVERLAY
2013-04-04 21:10:38 +00:00
void rarch_check_overlay ( void )
2012-12-22 14:33:28 +00:00
{
if ( ! driver . overlay )
return ;
static bool old_pressed ;
bool pressed = input_key_pressed_func ( RARCH_OVERLAY_NEXT ) ;
if ( pressed & & ! old_pressed )
input_overlay_next ( driver . overlay ) ;
old_pressed = pressed ;
}
2012-12-23 17:36:58 +00:00
# endif
2012-12-22 14:33:28 +00:00
2013-03-29 17:53:07 +00:00
# ifndef RARCH_CONSOLE
static void check_grab_mouse_toggle ( void )
{
static bool old_pressed ;
bool pressed = input_key_pressed_func ( RARCH_GRAB_MOUSE_TOGGLE ) & &
driver . input - > grab_mouse ;
static bool grab_mouse_state ;
if ( pressed & & ! old_pressed )
{
grab_mouse_state = ! grab_mouse_state ;
RARCH_LOG ( " Grab mouse state: %s. \n " , grab_mouse_state ? " yes " : " no " ) ;
driver . input - > grab_mouse ( driver . input_data , grab_mouse_state ) ;
if ( driver . video_poke & & driver . video_poke - > show_mouse )
driver . video_poke - > show_mouse ( driver . video_data , ! grab_mouse_state ) ;
}
old_pressed = pressed ;
}
# endif
2011-01-23 22:09:54 +00:00
static void do_state_checks ( void )
{
2013-12-09 15:18:58 +00:00
rarch_check_block_hotkey ( ) ;
2012-11-02 22:24:53 +00:00
2012-08-20 01:30:09 +00:00
# if defined(HAVE_SCREENSHOTS) && !defined(_XBOX)
2011-10-23 10:38:11 +00:00
check_screenshot ( ) ;
2012-01-26 02:00:56 +00:00
# endif
2011-11-26 14:54:58 +00:00
check_mute ( ) ;
2012-11-03 13:15:03 +00:00
check_volume ( ) ;
2011-11-26 14:54:58 +00:00
2012-10-01 20:15:48 +00:00
check_turbo ( ) ;
2012-12-23 17:36:58 +00:00
2013-03-29 17:53:07 +00:00
# ifndef RARCH_CONSOLE
check_grab_mouse_toggle ( ) ;
# endif
2012-12-23 17:36:58 +00:00
# ifdef HAVE_OVERLAY
2013-04-04 21:10:38 +00:00
rarch_check_overlay ( ) ;
2012-12-23 17:36:58 +00:00
# endif
2012-10-01 20:15:48 +00:00
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2011-02-13 15:40:24 +00:00
if ( ! g_extern . netplay )
{
2011-11-30 15:41:00 +00:00
# endif
2011-02-13 15:40:24 +00:00
check_pause ( ) ;
2011-10-17 19:30:58 +00:00
check_oneshot ( ) ;
2011-10-18 12:39:54 +00:00
2014-02-08 15:27:09 +00:00
if ( rarch_check_fullscreen ( ) & & g_extern . is_paused )
2012-04-21 21:25:32 +00:00
rarch_render_cached_frame ( ) ;
2011-02-05 19:46:58 +00:00
2011-10-18 12:39:54 +00:00
if ( g_extern . is_paused & & ! g_extern . is_oneshot )
return ;
2012-12-17 21:45:29 +00:00
check_fast_forward_button ( ) ;
2011-01-23 22:09:54 +00:00
2012-03-10 13:08:04 +00:00
check_stateslots ( ) ;
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2012-03-10 13:08:04 +00:00
check_savestates ( g_extern . bsv . movie ) ;
2012-03-25 22:04:12 +00:00
# else
check_savestates ( false ) ;
# endif
2011-02-13 15:40:24 +00:00
2011-10-18 19:57:28 +00:00
check_rewind ( ) ;
2012-03-04 11:01:07 +00:00
check_slowmotion ( ) ;
2011-11-20 19:19:05 +00:00
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2012-03-10 17:31:25 +00:00
check_movie ( ) ;
2012-03-25 22:04:12 +00:00
# endif
2014-04-12 11:25:48 +00:00
2011-03-29 16:28:31 +00:00
check_shader_dir ( ) ;
2011-10-18 19:59:37 +00:00
check_cheats ( ) ;
2013-02-21 22:44:07 +00:00
check_disk ( ) ;
2011-05-17 17:20:41 +00:00
# ifdef HAVE_DYLIB
check_dsp_config ( ) ;
# endif
2011-10-18 19:59:37 +00:00
check_reset ( ) ;
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2011-02-02 11:10:27 +00:00
}
2011-10-18 12:39:54 +00:00
else
2012-01-21 13:24:38 +00:00
{
check_netplay_flip ( ) ;
2014-02-08 15:27:09 +00:00
rarch_check_fullscreen ( ) ;
2012-01-21 13:24:38 +00:00
}
2011-11-30 15:41:00 +00:00
# endif
2011-01-23 22:09:54 +00:00
}
2011-08-26 15:32:04 +00:00
static void init_state ( void )
{
g_extern . video_active = true ;
g_extern . audio_active = true ;
2013-09-22 09:08:09 +00:00
}
2013-04-27 10:32:03 +00:00
2013-09-22 09:08:09 +00:00
static void init_state_first ( void )
{
2013-10-22 13:08:17 +00:00
unsigned i ;
2013-09-22 09:08:09 +00:00
init_state ( ) ;
2013-10-22 13:08:17 +00:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2013-09-22 09:08:09 +00:00
g_settings . input . libretro_device [ i ] = RETRO_DEVICE_JOYPAD ;
2011-08-26 15:32:04 +00:00
}
2011-01-12 17:05:57 +00:00
2012-04-21 21:25:32 +00:00
void rarch_main_clear_state ( void )
2010-10-01 19:39:15 +00:00
{
2012-01-14 15:08:54 +00:00
memset ( & g_settings , 0 , sizeof ( g_settings ) ) ;
2012-02-06 14:51:35 +00:00
2012-11-26 15:59:00 +00:00
if ( g_extern . log_file )
fclose ( g_extern . log_file ) ;
2012-01-14 15:08:54 +00:00
memset ( & g_extern , 0 , sizeof ( g_extern ) ) ;
2012-02-06 14:51:35 +00:00
2013-09-22 09:08:09 +00:00
init_state_first ( ) ;
2012-01-14 15:08:54 +00:00
}
2011-08-26 15:32:04 +00:00
2013-01-09 06:07:46 +00:00
# ifdef HAVE_ZLIB
# define DEFAULT_EXT "ZIP|zip"
# else
# define DEFAULT_EXT ""
# endif
2013-01-08 21:52:56 +00:00
void rarch_init_system_info ( void )
2012-04-07 09:55:37 +00:00
{
struct retro_system_info * info = & g_extern . system . info ;
2012-04-07 10:17:40 +00:00
pretro_get_system_info ( info ) ;
2012-04-07 09:55:37 +00:00
if ( ! info - > library_name )
info - > library_name = " Unknown " ;
if ( ! info - > library_version )
info - > library_version = " v0 " ;
2013-01-23 02:20:58 +00:00
# ifdef RARCH_CONSOLE
snprintf ( g_extern . title_buf , sizeof ( g_extern . title_buf ) , " %s %s " ,
info - > library_name , info - > library_version ) ;
# else
2012-04-21 21:13:50 +00:00
snprintf ( g_extern . title_buf , sizeof ( g_extern . title_buf ) , " RetroArch : %s %s " ,
2012-04-07 09:55:37 +00:00
info - > library_name , info - > library_version ) ;
2013-01-23 02:20:58 +00:00
# endif
2013-01-09 10:26:21 +00:00
strlcpy ( g_extern . system . valid_extensions , info - > valid_extensions ? info - > valid_extensions : DEFAULT_EXT ,
sizeof ( g_extern . system . valid_extensions ) ) ;
2013-01-10 07:46:46 +00:00
g_extern . system . block_extract = info - > block_extract ;
2012-04-07 09:55:37 +00:00
}
static void init_system_av_info ( void )
{
2012-04-07 10:17:40 +00:00
pretro_get_system_av_info ( & g_extern . system . av_info ) ;
2013-08-07 20:24:12 +00:00
g_extern . frame_limit . last_frame_time = rarch_get_time_usec ( ) ;
2013-12-17 18:10:21 +00:00
g_extern . frame_limit . minimum_frame_time = ( retro_time_t ) roundf ( 1000000.0f / ( g_extern . system . av_info . timing . fps * g_settings . fastforward_ratio ) ) ;
2012-04-07 09:55:37 +00:00
}
static void verify_api_version ( void )
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Version of libretro API: %u \n " , pretro_api_version ( ) ) ;
RARCH_LOG ( " Compiled against API: %u \n " , RETRO_API_VERSION ) ;
2012-04-07 09:55:37 +00:00
if ( pretro_api_version ( ) ! = RETRO_API_VERSION )
2012-04-21 21:25:32 +00:00
RARCH_WARN ( " RetroArch is compiled against a different version of libretro than this libretro implementation. \n " ) ;
2012-04-07 09:55:37 +00:00
}
2012-11-01 21:31:24 +00:00
// Make sure we haven't compiled for something we cannot run.
// Ideally, code would get swapped out depending on CPU support, but this will do for now.
static void validate_cpu_features ( void )
{
2013-12-18 18:10:57 +00:00
uint64_t cpu = rarch_get_cpu_features ( ) ;
2013-12-19 02:45:17 +00:00
( void ) cpu ;
2012-11-01 21:31:24 +00:00
2012-11-02 20:25:54 +00:00
# define FAIL_CPU(simd_type) do { \
RARCH_ERR ( simd_type " code is compiled in, but CPU does not support this feature. Cannot continue. \n " ) ; \
rarch_fail ( 1 , " validate_cpu_features() " ) ; \
} while ( 0 )
# ifdef __SSE__
2013-12-17 18:10:21 +00:00
if ( ! ( cpu & RETRO_SIMD_SSE ) )
2012-11-02 20:25:54 +00:00
FAIL_CPU ( " SSE " ) ;
# endif
2012-11-01 21:31:24 +00:00
# ifdef __SSE2__
2013-12-17 18:10:21 +00:00
if ( ! ( cpu & RETRO_SIMD_SSE2 ) )
2012-11-02 20:25:54 +00:00
FAIL_CPU ( " SSE2 " ) ;
2012-11-01 21:31:24 +00:00
# endif
# ifdef __AVX__
2013-12-17 18:10:21 +00:00
if ( ! ( cpu & RETRO_SIMD_AVX ) )
2012-11-02 20:25:54 +00:00
FAIL_CPU ( " AVX " ) ;
2012-11-01 21:31:24 +00:00
# endif
}
2012-04-21 21:25:32 +00:00
int rarch_main_init ( int argc , char * argv [ ] )
2012-01-14 15:08:54 +00:00
{
init_state ( ) ;
2011-12-25 20:39:58 +00:00
2012-01-14 15:08:54 +00:00
int sjlj_ret ;
if ( ( sjlj_ret = setjmp ( g_extern . error_sjlj_context ) ) > 0 )
{
2014-04-12 11:25:48 +00:00
RARCH_ERR ( " Fatal error received in: \" %s \" \n " , g_extern . error_string ) ;
2012-01-14 15:08:54 +00:00
return sjlj_ret ;
}
g_extern . error_in_init = true ;
2012-05-03 22:14:42 +00:00
parse_input ( argc , argv ) ;
2011-12-25 20:39:58 +00:00
if ( g_extern . verbose )
{
2012-10-16 11:57:35 +00:00
RARCH_LOG_OUTPUT ( " === Build ======================================= " ) ;
2011-12-25 20:39:58 +00:00
print_compiler ( stderr ) ;
2014-01-11 17:51:42 +00:00
RARCH_LOG_OUTPUT ( " Version: %s \n " , PACKAGE_VERSION ) ;
# ifdef HAVE_GIT_VERSION
RARCH_LOG_OUTPUT ( " Git: %s \n " , rarch_git_version ) ;
# endif
2012-10-16 11:57:35 +00:00
RARCH_LOG_OUTPUT ( " ================================================= \n " ) ;
2011-12-25 20:39:58 +00:00
}
2012-11-01 21:31:24 +00:00
validate_cpu_features ( ) ;
2012-01-28 14:47:02 +00:00
config_load ( ) ;
2010-12-30 12:54:49 +00:00
2013-04-14 14:24:19 +00:00
init_libretro_sym ( g_extern . libretro_dummy ) ;
2013-01-08 21:52:56 +00:00
rarch_init_system_info ( ) ;
2012-04-07 09:55:37 +00:00
init_drivers_pre ( ) ;
2010-12-30 13:11:56 +00:00
2012-04-07 09:55:37 +00:00
verify_api_version ( ) ;
pretro_init ( ) ;
2010-10-01 19:39:15 +00:00
2013-04-30 22:56:13 +00:00
g_extern . use_sram = ! g_extern . libretro_dummy & & ! g_extern . libretro_no_rom ;
2012-03-25 22:04:12 +00:00
bool allow_cheats = true ;
2011-12-24 12:46:12 +00:00
2013-04-30 22:56:13 +00:00
if ( g_extern . libretro_no_rom & & ! g_extern . libretro_dummy )
{
2014-04-04 12:58:42 +00:00
if ( ! init_rom_file ( ) )
2013-04-30 22:56:13 +00:00
goto error ;
}
else if ( ! g_extern . libretro_dummy )
2013-04-14 14:24:19 +00:00
{
fill_pathnames ( ) ;
2013-01-24 15:49:23 +00:00
2014-04-04 12:58:42 +00:00
if ( ! init_rom_file ( ) )
2013-04-14 14:24:19 +00:00
goto error ;
2010-10-01 19:39:15 +00:00
2013-04-14 14:24:19 +00:00
set_savestate_auto_index ( ) ;
2013-01-18 18:11:41 +00:00
2013-04-14 14:24:19 +00:00
if ( ! g_extern . sram_load_disable )
load_save_files ( ) ;
else
RARCH_LOG ( " Skipping SRAM load. \n " ) ;
2011-11-20 19:19:05 +00:00
2013-04-14 14:24:19 +00:00
load_auto_state ( ) ;
2012-04-01 14:58:53 +00:00
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2013-04-14 14:24:19 +00:00
init_movie ( ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-02-25 10:47:27 +00:00
2011-03-19 19:41:07 +00:00
# ifdef HAVE_NETPLAY
2013-04-14 14:24:19 +00:00
init_netplay ( ) ;
2012-05-27 12:23:30 +00:00
# endif
2013-04-14 14:24:19 +00:00
}
2012-05-27 12:23:30 +00:00
2013-07-14 11:09:53 +00:00
init_libretro_cbs ( ) ;
2013-04-14 14:24:19 +00:00
init_system_av_info ( ) ;
2011-02-13 17:19:37 +00:00
init_drivers ( ) ;
2010-10-01 19:39:15 +00:00
2012-07-24 00:47:28 +00:00
# ifdef HAVE_COMMAND
init_command ( ) ;
# endif
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2011-02-25 10:47:27 +00:00
if ( ! g_extern . netplay )
2011-11-30 15:41:00 +00:00
# endif
2013-03-16 13:28:10 +00:00
rarch_init_rewind ( ) ;
2014-04-12 11:25:48 +00:00
2011-01-10 13:29:00 +00:00
init_controllers ( ) ;
2014-04-12 11:25:48 +00:00
2011-01-05 19:07:55 +00:00
# ifdef HAVE_FFMPEG
2014-02-20 21:48:31 +00:00
rarch_init_recording ( ) ;
2011-01-05 19:07:55 +00:00
# endif
2011-01-03 19:46:50 +00:00
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2013-04-14 14:24:19 +00:00
g_extern . use_sram = g_extern . use_sram & & ! g_extern . sram_save_disable & & ! g_extern . netplay_is_client ;
2011-11-30 15:41:00 +00:00
# else
2013-04-14 14:24:19 +00:00
g_extern . use_sram = g_extern . use_sram & & ! g_extern . sram_save_disable ;
2011-11-30 15:41:00 +00:00
# endif
2011-11-20 19:19:05 +00:00
2012-01-14 13:08:43 +00:00
if ( ! g_extern . use_sram )
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " SRAM will not be saved. \n " ) ;
2011-11-18 17:03:24 +00:00
2013-11-08 00:54:46 +00:00
# if defined(HAVE_THREADS)
2012-01-14 13:08:43 +00:00
if ( g_extern . use_sram )
2013-04-29 13:56:49 +00:00
rarch_init_autosave ( ) ;
2012-03-26 01:24:28 +00:00
# endif
2014-04-12 11:25:48 +00:00
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2012-03-25 22:04:12 +00:00
allow_cheats & = ! g_extern . netplay ;
2011-11-30 15:41:00 +00:00
# endif
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
allow_cheats & = ! g_extern . bsv . movie ;
# endif
if ( allow_cheats )
2011-09-06 09:55:21 +00:00
init_cheats ( ) ;
2011-01-23 01:23:20 +00:00
2012-01-14 15:08:54 +00:00
g_extern . error_in_init = false ;
2013-01-05 22:44:49 +00:00
g_extern . main_is_init = true ;
2012-01-14 13:08:43 +00:00
return 0 ;
2011-08-13 02:09:08 +00:00
2012-01-14 13:08:43 +00:00
error :
2013-07-15 19:35:47 +00:00
uninit_drivers ( ) ;
2012-04-07 09:55:37 +00:00
pretro_unload_game ( ) ;
pretro_deinit ( ) ;
uninit_libretro_sym ( ) ;
2010-05-26 19:27:37 +00:00
2013-01-05 22:51:13 +00:00
g_extern . main_is_init = false ;
2012-01-14 13:08:43 +00:00
return 1 ;
}
2013-03-10 20:13:17 +00:00
static inline bool check_enter_rgui ( void )
{
static bool old_rmenu_toggle = true ;
2013-04-14 14:24:19 +00:00
// Always go into menu if dummy core is loaded.
bool rmenu_toggle = input_key_pressed_func ( RARCH_MENU_TOGGLE ) | | ( g_extern . libretro_dummy & & ! old_rmenu_toggle ) ;
2013-03-10 20:13:17 +00:00
if ( rmenu_toggle & & ! old_rmenu_toggle )
{
2013-12-28 20:08:30 +00:00
g_extern . lifecycle_state | = ( 1ULL < < MODE_MENU_PREINIT ) ;
2013-03-10 20:13:17 +00:00
old_rmenu_toggle = true ;
2013-07-14 11:43:01 +00:00
g_extern . system . frame_time_last = 0 ;
2013-03-10 20:13:17 +00:00
return true ;
}
else
{
old_rmenu_toggle = rmenu_toggle ;
return false ;
}
}
2013-07-14 11:09:53 +00:00
static inline void update_frame_time ( void )
{
2013-07-14 11:43:01 +00:00
if ( ! g_extern . system . frame_time . callback )
2013-07-14 11:09:53 +00:00
return ;
2013-12-17 18:10:21 +00:00
retro_time_t time = rarch_get_time_usec ( ) ;
retro_time_t delta = 0 ;
2013-07-14 11:43:01 +00:00
2013-07-15 18:36:18 +00:00
bool is_locked_fps = g_extern . is_paused | | driver . nonblock_state ;
# ifdef HAVE_FFMPEG
is_locked_fps | = g_extern . recording ;
# endif
2014-04-12 11:25:48 +00:00
2013-07-14 11:43:01 +00:00
if ( ! g_extern . system . frame_time_last | | is_locked_fps )
delta = g_extern . system . frame_time . reference ;
2013-07-14 11:09:53 +00:00
else
delta = time - g_extern . system . frame_time_last ;
2013-07-14 11:53:05 +00:00
if ( ! is_locked_fps & & g_extern . is_slowmotion )
delta / = g_settings . slowmotion_ratio ;
2013-07-14 11:43:01 +00:00
g_extern . system . frame_time_last = is_locked_fps ? 0 : time ;
g_extern . system . frame_time . callback ( delta ) ;
2013-07-14 11:09:53 +00:00
}
2013-08-07 20:24:12 +00:00
static inline void limit_frame_time ( void )
{
if ( g_settings . fastforward_ratio < 0.0f )
return ;
2013-12-17 18:10:21 +00:00
retro_time_t current = rarch_get_time_usec ( ) ;
retro_time_t target = g_extern . frame_limit . last_frame_time + g_extern . frame_limit . minimum_frame_time ;
retro_time_t to_sleep_ms = ( target - current ) / 1000 ;
2013-08-07 20:24:12 +00:00
if ( to_sleep_ms > 0 )
{
2013-09-27 16:43:08 +00:00
rarch_sleep ( ( unsigned int ) to_sleep_ms ) ;
2013-08-07 20:24:12 +00:00
g_extern . frame_limit . last_frame_time + = g_extern . frame_limit . minimum_frame_time ; // Combat jitter a bit.
}
else
g_extern . frame_limit . last_frame_time = rarch_get_time_usec ( ) ;
}
2012-04-21 21:25:32 +00:00
bool rarch_main_iterate ( void )
2012-01-14 13:08:43 +00:00
{
2014-01-08 16:31:14 +00:00
unsigned i ;
2012-03-21 21:12:18 +00:00
# ifdef HAVE_DYLIB
2012-01-14 13:08:43 +00:00
// DSP plugin GUI events.
if ( g_extern . audio_data . dsp_handle & & g_extern . audio_data . dsp_plugin - > events )
g_extern . audio_data . dsp_plugin - > events ( g_extern . audio_data . dsp_handle ) ;
2012-03-21 21:12:18 +00:00
# endif
2012-01-14 13:08:43 +00:00
2012-05-22 18:25:03 +00:00
// SHUTDOWN on consoles should exit RetroArch completely.
if ( g_extern . system . shutdown )
return false ;
2012-01-14 13:08:43 +00:00
// Time to drop?
2013-03-07 18:02:44 +00:00
if ( input_key_pressed_func ( RARCH_QUIT_KEY ) | | ! video_alive_func ( ) )
return false ;
2013-03-10 20:13:17 +00:00
if ( check_enter_rgui ( ) )
return false ; // Enter menu, don't exit.
2012-01-14 13:08:43 +00:00
2013-08-25 13:51:42 +00:00
if ( g_extern . exec )
{
g_extern . exec = false ;
return false ;
}
2012-01-14 13:08:43 +00:00
// Checks for stuff like fullscreen, save states, etc.
do_state_checks ( ) ;
2012-04-07 10:20:37 +00:00
// Run libretro for one frame.
2013-11-08 00:54:46 +00:00
# if defined(HAVE_THREADS)
2012-12-15 19:44:59 +00:00
lock_autosave ( ) ;
2011-11-30 16:46:58 +00:00
# endif
2011-02-14 15:10:53 +00:00
2011-03-19 19:41:07 +00:00
# ifdef HAVE_NETPLAY
2012-12-15 19:44:59 +00:00
if ( g_extern . netplay )
netplay_pre_frame ( g_extern . netplay ) ;
2011-03-19 19:41:07 +00:00
# endif
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2012-12-15 19:44:59 +00:00
if ( g_extern . bsv . movie )
bsv_movie_set_frame_start ( g_extern . bsv . movie ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-02-14 15:10:53 +00:00
2013-11-12 15:00:18 +00:00
# ifdef HAVE_CAMERA
if ( g_extern . system . camera_callback . caps )
driver_camera_poll ( ) ;
# endif
2014-01-08 16:31:14 +00:00
// Update binds for analog dpad modes.
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2014-01-08 16:47:07 +00:00
{
2014-01-08 16:31:14 +00:00
input_push_analog_dpad ( g_settings . input . binds [ i ] , g_settings . input . analog_dpad_mode [ i ] ) ;
2014-01-08 16:47:07 +00:00
input_push_analog_dpad ( g_settings . input . autoconf_binds [ i ] , g_settings . input . analog_dpad_mode [ i ] ) ;
}
2014-01-08 16:31:14 +00:00
2013-07-14 11:09:53 +00:00
update_frame_time ( ) ;
2012-12-15 19:44:59 +00:00
pretro_run ( ) ;
2013-08-07 20:24:12 +00:00
limit_frame_time ( ) ;
2011-02-14 15:10:53 +00:00
2014-01-08 16:31:14 +00:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2014-01-08 16:47:07 +00:00
{
2014-01-08 16:31:14 +00:00
input_pop_analog_dpad ( g_settings . input . binds [ i ] ) ;
2014-01-08 16:47:07 +00:00
input_pop_analog_dpad ( g_settings . input . autoconf_binds [ i ] ) ;
}
2014-01-08 16:31:14 +00:00
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2012-12-15 19:44:59 +00:00
if ( g_extern . bsv . movie )
bsv_movie_set_frame_end ( g_extern . bsv . movie ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-03-19 19:41:07 +00:00
# ifdef HAVE_NETPLAY
2012-12-15 19:44:59 +00:00
if ( g_extern . netplay )
netplay_post_frame ( g_extern . netplay ) ;
2011-03-19 19:41:07 +00:00
# endif
2011-02-14 15:10:53 +00:00
2013-11-08 00:54:46 +00:00
# if defined(HAVE_THREADS)
2012-12-15 19:44:59 +00:00
unlock_autosave ( ) ;
2012-03-21 21:12:18 +00:00
# endif
2012-01-14 13:08:43 +00:00
return true ;
}
2010-05-26 19:27:37 +00:00
2012-04-21 21:25:32 +00:00
void rarch_main_deinit ( void )
2012-01-14 13:08:43 +00:00
{
2011-03-19 19:41:07 +00:00
# ifdef HAVE_NETPLAY
2011-02-13 15:40:24 +00:00
deinit_netplay ( ) ;
2012-05-27 12:23:30 +00:00
# endif
2012-07-24 00:47:28 +00:00
# ifdef HAVE_COMMAND
deinit_command ( ) ;
2011-03-19 19:41:07 +00:00
# endif
2011-02-13 16:45:14 +00:00
2013-11-08 00:54:46 +00:00
# if defined(HAVE_THREADS)
2012-01-14 13:08:43 +00:00
if ( g_extern . use_sram )
2013-04-29 13:56:49 +00:00
rarch_deinit_autosave ( ) ;
2012-03-26 01:24:28 +00:00
# endif
2011-02-10 20:16:59 +00:00
2011-01-05 19:07:55 +00:00
# ifdef HAVE_FFMPEG
2014-02-20 21:48:31 +00:00
rarch_deinit_recording ( ) ;
2011-01-05 19:07:55 +00:00
# endif
2011-01-03 19:46:50 +00:00
2012-01-14 13:08:43 +00:00
if ( g_extern . use_sram )
2011-02-02 11:10:27 +00:00
save_files ( ) ;
2011-02-25 10:47:27 +00:00
2011-11-30 15:41:00 +00:00
# ifdef HAVE_NETPLAY
2011-02-25 10:47:27 +00:00
if ( ! g_extern . netplay )
2011-11-30 15:41:00 +00:00
# endif
2013-03-16 13:28:10 +00:00
rarch_deinit_rewind ( ) ;
2010-05-26 19:27:37 +00:00
2011-04-17 11:30:59 +00:00
deinit_cheats ( ) ;
2012-03-25 22:04:12 +00:00
# ifdef HAVE_BSV_MOVIE
2011-02-02 11:10:27 +00:00
deinit_movie ( ) ;
2012-03-25 22:04:12 +00:00
# endif
2011-02-02 11:45:56 +00:00
2013-04-30 22:56:13 +00:00
if ( ! g_extern . libretro_dummy & & ! g_extern . libretro_no_rom )
2013-04-14 14:24:19 +00:00
save_auto_state ( ) ;
2012-06-02 19:33:37 +00:00
2013-07-15 19:35:47 +00:00
uninit_drivers ( ) ;
2012-04-07 09:55:37 +00:00
pretro_unload_game ( ) ;
pretro_deinit ( ) ;
uninit_libretro_sym ( ) ;
2013-01-05 22:44:49 +00:00
2014-04-04 12:58:42 +00:00
if ( g_extern . temporary_roms )
2013-01-21 22:51:56 +00:00
{
2014-04-04 12:58:42 +00:00
unsigned i ;
for ( i = 0 ; i < g_extern . temporary_roms - > size ; i + + )
{
const char * path = g_extern . temporary_roms - > elems [ i ] . data ;
RARCH_LOG ( " Removing temporary ROM file: %s. \n " , path ) ;
if ( remove ( path ) < 0 )
RARCH_ERR ( " Failed to remove temporary file: %s. \n " , path ) ;
}
2013-01-21 22:51:56 +00:00
}
2014-04-04 12:58:42 +00:00
string_list_free ( g_extern . temporary_roms ) ;
g_extern . temporary_roms = NULL ;
string_list_free ( g_extern . subsystem_fullpaths ) ;
string_list_free ( g_extern . savefiles ) ;
g_extern . subsystem_fullpaths = NULL ;
g_extern . savefiles = NULL ;
2013-01-21 22:51:56 +00:00
2013-01-05 22:51:13 +00:00
g_extern . main_is_init = false ;
2012-01-14 13:08:43 +00:00
}
2010-05-26 19:27:37 +00:00
2013-01-06 02:06:47 +00:00
# define MAX_ARGS 32
2013-02-25 06:01:16 +00:00
2013-01-06 02:06:47 +00:00
int rarch_main_init_wrap ( const struct rarch_main_wrap * args )
{
2013-10-22 13:08:17 +00:00
unsigned i ;
2013-01-06 02:06:47 +00:00
if ( g_extern . main_is_init )
rarch_main_deinit ( ) ;
int argc = 0 ;
char * argv [ MAX_ARGS ] = { NULL } ;
char * argv_copy [ MAX_ARGS ] ;
argv [ argc + + ] = strdup ( " retroarch " ) ;
2013-05-02 12:42:58 +00:00
if ( ! args - > no_rom )
2013-04-22 18:35:45 +00:00
{
2013-05-02 12:42:58 +00:00
if ( args - > rom_path )
{
RARCH_LOG ( " Using ROM: %s. \n " , args - > rom_path ) ;
argv [ argc + + ] = strdup ( args - > rom_path ) ;
}
else
{
RARCH_LOG ( " No ROM, starting dummy core. \n " ) ;
argv [ argc + + ] = strdup ( " --menu " ) ;
}
2013-04-22 18:35:45 +00:00
}
2013-01-06 02:06:47 +00:00
if ( args - > sram_path )
{
argv [ argc + + ] = strdup ( " -s " ) ;
argv [ argc + + ] = strdup ( args - > sram_path ) ;
}
if ( args - > state_path )
{
argv [ argc + + ] = strdup ( " -S " ) ;
argv [ argc + + ] = strdup ( args - > state_path ) ;
}
if ( args - > config_path )
{
argv [ argc + + ] = strdup ( " -c " ) ;
argv [ argc + + ] = strdup ( args - > config_path ) ;
}
2013-01-06 03:11:24 +00:00
# ifdef HAVE_DYNAMIC
2013-01-06 02:06:47 +00:00
if ( args - > libretro_path )
{
argv [ argc + + ] = strdup ( " -L " ) ;
argv [ argc + + ] = strdup ( args - > libretro_path ) ;
}
2013-01-06 03:11:24 +00:00
# endif
2013-01-06 02:06:47 +00:00
if ( args - > verbose )
argv [ argc + + ] = strdup ( " -v " ) ;
# ifdef HAVE_FILE_LOGGER
2013-10-22 13:08:17 +00:00
for ( i = 0 ; i < argc ; i + + )
2013-01-06 02:06:47 +00:00
RARCH_LOG ( " arg #%d: %s \n " , i , argv [ i ] ) ;
# endif
// The pointers themselves are not const, and can be messed around with by getopt_long().
memcpy ( argv_copy , argv , sizeof ( argv ) ) ;
int ret = rarch_main_init ( argc , argv ) ;
2013-10-22 13:08:17 +00:00
for ( i = 0 ; i < ARRAY_SIZE ( argv_copy ) ; i + + )
2013-01-06 02:06:47 +00:00
free ( argv_copy [ i ] ) ;
return ret ;
}
2013-02-25 06:01:16 +00:00
bool rarch_main_idle_iterate ( void )
2013-01-06 02:50:55 +00:00
{
2013-02-25 06:01:16 +00:00
if ( input_key_pressed_func ( RARCH_QUIT_KEY ) | | ! video_alive_func ( ) )
2013-01-06 02:50:55 +00:00
return false ;
do_state_checks ( ) ;
2013-03-16 09:35:22 +00:00
rarch_input_poll ( ) ;
2013-01-06 02:50:55 +00:00
rarch_sleep ( 10 ) ;
return true ;
}