2019-02-06 21:28:04 +00:00
/*
Copyright 2019 flyinghead
This file is part of reicast .
reicast is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 2 of the License , or
( at your option ) any later version .
reicast is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with reicast . If not , see < https : //www.gnu.org/licenses/>.
*/
2019-02-06 18:57:13 +00:00
2020-04-22 17:11:49 +00:00
# include <mutex>
2019-03-04 23:54:01 +00:00
# include "gui.h"
2019-02-06 18:57:13 +00:00
# include "cfg/cfg.h"
2019-03-25 17:46:57 +00:00
# include "hw/maple/maple_if.h"
2020-03-20 15:57:50 +00:00
# include "hw/maple/maple_devs.h"
2020-03-25 01:26:00 +00:00
# include "hw/naomi/naomi_cart.h"
2019-02-06 18:57:13 +00:00
# include "imgui/imgui.h"
2019-02-19 16:43:25 +00:00
# include "gles/imgui_impl_opengl3.h"
2019-02-06 18:57:13 +00:00
# include "imgui/roboto_medium.h"
2020-04-22 20:28:12 +00:00
# include "network/naomi_network.h"
2019-02-06 18:57:13 +00:00
# include "gles/gles.h"
2019-02-12 10:30:24 +00:00
# include "input/gamepad_device.h"
2019-02-25 16:52:53 +00:00
# include "input/keyboard_device.h"
# include "gui_util.h"
2019-03-04 23:54:01 +00:00
# include "gui_android.h"
2020-04-09 09:44:19 +00:00
# include "game_scanner.h"
2019-04-12 20:59:39 +00:00
# include "version.h"
2019-04-05 20:22:46 +00:00
# include "oslib/audiostream.h"
2020-01-30 17:59:26 +00:00
# include "imgread/common.h"
2020-04-02 10:20:03 +00:00
# include "log/LogManager.h"
2020-04-20 16:52:02 +00:00
# include "emulator.h"
2019-02-06 18:57:13 +00:00
2019-02-07 15:59:24 +00:00
extern void UpdateInputState ( u32 port ) ;
2019-02-25 16:52:53 +00:00
extern bool game_started ;
2019-02-06 18:57:13 +00:00
extern int screen_width , screen_height ;
extern u8 kb_shift ; // shift keys pressed (bitmask)
extern u8 kb_key [ 6 ] ; // normal keys pressed
int screen_dpi = 96 ;
static bool inited = false ;
2019-02-12 10:30:24 +00:00
static float scaling = 1 ;
2019-03-04 23:54:01 +00:00
GuiState gui_state = Main ;
2019-02-06 18:57:13 +00:00
static bool settings_opening ;
2020-03-29 18:58:49 +00:00
# ifdef __ANDROID__
2019-02-06 18:57:13 +00:00
static bool touch_up ;
2020-03-29 18:58:49 +00:00
# endif
2019-07-13 08:59:20 +00:00
static std : : string error_msg ;
2020-04-20 16:52:02 +00:00
static std : : string osd_message ;
static double osd_message_end ;
2020-04-22 17:11:49 +00:00
static std : : mutex osd_message_mutex ;
2019-02-06 18:57:13 +00:00
2019-03-29 16:35:00 +00:00
static void display_vmus ( ) ;
static void reset_vmus ( ) ;
static void term_vmus ( ) ;
2020-04-09 09:44:19 +00:00
GameScanner scanner ;
2019-12-25 12:09:54 +00:00
float gui_get_scaling ( )
{
return scaling ;
}
2019-02-06 18:57:13 +00:00
void gui_init ( )
{
if ( inited )
return ;
inited = true ;
// Setup Dear ImGui context
IMGUI_CHECKVERSION ( ) ;
ImGui : : CreateContext ( ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ; ( void ) io ;
2019-02-12 10:30:24 +00:00
io . IniFilename = NULL ;
2019-02-06 18:57:13 +00:00
io . ConfigFlags | = ImGuiConfigFlags_NavEnableKeyboard ; // Enable Keyboard Controls
2019-02-07 15:59:24 +00:00
io . ConfigFlags | = ImGuiConfigFlags_NavEnableGamepad ; // Enable Gamepad Controls
2019-02-06 18:57:13 +00:00
io . KeyMap [ ImGuiKey_Tab ] = 0x2B ;
io . KeyMap [ ImGuiKey_LeftArrow ] = 0x50 ;
io . KeyMap [ ImGuiKey_RightArrow ] = 0x4F ;
io . KeyMap [ ImGuiKey_UpArrow ] = 0x52 ;
io . KeyMap [ ImGuiKey_DownArrow ] = 0x51 ;
io . KeyMap [ ImGuiKey_PageUp ] = 0x4B ;
io . KeyMap [ ImGuiKey_PageDown ] = 0x4E ;
io . KeyMap [ ImGuiKey_Home ] = 0x4A ;
io . KeyMap [ ImGuiKey_End ] = 0x4D ;
io . KeyMap [ ImGuiKey_Insert ] = 0x49 ;
io . KeyMap [ ImGuiKey_Delete ] = 0x4C ;
io . KeyMap [ ImGuiKey_Backspace ] = 0x2A ;
io . KeyMap [ ImGuiKey_Space ] = 0x2C ;
io . KeyMap [ ImGuiKey_Enter ] = 0x28 ;
io . KeyMap [ ImGuiKey_Escape ] = 0x29 ;
io . KeyMap [ ImGuiKey_A ] = 0x04 ;
io . KeyMap [ ImGuiKey_C ] = 0x06 ;
io . KeyMap [ ImGuiKey_V ] = 0x19 ;
io . KeyMap [ ImGuiKey_X ] = 0x1B ;
io . KeyMap [ ImGuiKey_Y ] = 0x1C ;
io . KeyMap [ ImGuiKey_Z ] = 0x1D ;
// Setup Dear ImGui style
ImGui : : StyleColorsDark ( ) ;
//ImGui::StyleColorsClassic();
2019-02-12 10:30:24 +00:00
ImGui : : GetStyle ( ) . TabRounding = 0 ;
2019-02-09 20:20:03 +00:00
ImGui : : GetStyle ( ) . ItemSpacing = ImVec2 ( 8 , 8 ) ; // from 8,4
ImGui : : GetStyle ( ) . ItemInnerSpacing = ImVec2 ( 4 , 6 ) ; // from 4,4
2019-02-12 10:30:24 +00:00
//ImGui::GetStyle().WindowRounding = 0;
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2019-02-09 20:20:03 +00:00
ImGui : : GetStyle ( ) . GrabMinSize = 20.0f ; // from 10
ImGui : : GetStyle ( ) . ScrollbarSize = 24.0f ; // from 16
ImGui : : GetStyle ( ) . TouchExtraPadding = ImVec2 ( 1 , 1 ) ; // from 0,0
# endif
2019-02-06 18:57:13 +00:00
// Setup Platform/Renderer bindings
2019-10-05 09:50:14 +00:00
if ( settings . pvr . IsOpenGL ( ) )
ImGui_ImplOpenGL3_Init ( ) ;
2019-02-06 18:57:13 +00:00
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//io.Fonts->AddFontDefault();
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != NULL);
2020-03-29 17:29:14 +00:00
scaling = std : : max ( 1.f , screen_dpi / 100.f * 0.75f ) ;
2019-02-06 18:57:13 +00:00
if ( scaling > 1 )
ImGui : : GetStyle ( ) . ScaleAllSizes ( scaling ) ;
io . Fonts - > AddFontFromMemoryCompressedTTF ( roboto_medium_compressed_data , roboto_medium_compressed_size , 17 * scaling ) ;
2019-07-01 15:17:08 +00:00
INFO_LOG ( RENDERER , " Screen DPI is %d, size %d x %d. Scaling by %.2f " , screen_dpi , screen_width , screen_height , scaling ) ;
2019-02-06 18:57:13 +00:00
}
2019-03-04 23:54:01 +00:00
void ImGui_Impl_NewFrame ( )
2019-02-06 18:57:13 +00:00
{
2019-10-05 09:50:14 +00:00
if ( settings . pvr . IsOpenGL ( ) )
ImGui_ImplOpenGL3_NewFrame ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : GetIO ( ) . DisplaySize . x = screen_width ;
ImGui : : GetIO ( ) . DisplaySize . y = screen_height ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2019-02-07 15:59:24 +00:00
UpdateInputState ( 0 ) ;
2019-02-06 18:57:13 +00:00
// Read keyboard modifiers inputs
io . KeyCtrl = ( kb_shift & ( 0x01 | 0x10 ) ) ! = 0 ;
io . KeyShift = ( kb_shift & ( 0x02 | 0x20 ) ) ! = 0 ;
io . KeyAlt = false ;
io . KeySuper = false ;
memset ( & io . KeysDown [ 0 ] , 0 , sizeof ( io . KeysDown ) ) ;
for ( int i = 0 ; i < IM_ARRAYSIZE ( kb_key ) ; i + + )
if ( kb_key [ i ] ! = 0 )
io . KeysDown [ kb_key [ i ] ] = true ;
else
break ;
float scale = screen_height / 480.0f ;
float x_offset = ( screen_width - 640.0f * scale ) / 2 ;
int real_x = mo_x_abs * scale + x_offset ;
int real_y = mo_y_abs * scale ;
if ( real_x < 0 | | real_x > = screen_width | | real_y < 0 | | real_y > = screen_height )
io . MousePos = ImVec2 ( - FLT_MAX , - FLT_MAX ) ;
else
io . MousePos = ImVec2 ( real_x , real_y ) ;
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2019-02-06 18:57:13 +00:00
// Put the "mouse" outside the screen one frame after a touch up
// This avoids buttons and the like to stay selected
if ( ( mo_buttons & 0xf ) = = 0xf )
{
if ( touch_up )
{
io . MousePos = ImVec2 ( - FLT_MAX , - FLT_MAX ) ;
touch_up = false ;
}
else if ( io . MouseDown [ 0 ] )
touch_up = true ;
}
# endif
2019-02-25 16:52:53 +00:00
if ( io . WantCaptureMouse )
{
io . MouseWheel = - mo_wheel_delta / 16 ;
// Reset all relative mouse positions
mo_x_delta = 0 ;
mo_y_delta = 0 ;
mo_wheel_delta = 0 ;
}
2019-02-06 18:57:13 +00:00
io . MouseDown [ 0 ] = ( mo_buttons & ( 1 < < 2 ) ) = = 0 ;
io . MouseDown [ 1 ] = ( mo_buttons & ( 1 < < 1 ) ) = = 0 ;
io . MouseDown [ 2 ] = ( mo_buttons & ( 1 < < 3 ) ) = = 0 ;
io . MouseDown [ 3 ] = ( mo_buttons & ( 1 < < 0 ) ) = = 0 ;
2019-02-07 15:59:24 +00:00
io . NavInputs [ ImGuiNavInput_Activate ] = ( kcode [ 0 ] & DC_BTN_A ) = = 0 ;
io . NavInputs [ ImGuiNavInput_Cancel ] = ( kcode [ 0 ] & DC_BTN_B ) = = 0 ;
io . NavInputs [ ImGuiNavInput_Input ] = ( kcode [ 0 ] & DC_BTN_X ) = = 0 ;
io . NavInputs [ ImGuiNavInput_DpadLeft ] = ( kcode [ 0 ] & DC_DPAD_LEFT ) = = 0 ;
io . NavInputs [ ImGuiNavInput_DpadRight ] = ( kcode [ 0 ] & DC_DPAD_RIGHT ) = = 0 ;
io . NavInputs [ ImGuiNavInput_DpadUp ] = ( kcode [ 0 ] & DC_DPAD_UP ) = = 0 ;
io . NavInputs [ ImGuiNavInput_DpadDown ] = ( kcode [ 0 ] & DC_DPAD_DOWN ) = = 0 ;
io . NavInputs [ ImGuiNavInput_LStickLeft ] = joyx [ 0 ] < 0 ? - ( float ) joyx [ 0 ] / 128 : 0.f ;
2019-02-21 11:46:00 +00:00
if ( io . NavInputs [ ImGuiNavInput_LStickLeft ] < 0.1f )
2019-02-07 15:59:24 +00:00
io . NavInputs [ ImGuiNavInput_LStickLeft ] = 0.f ;
io . NavInputs [ ImGuiNavInput_LStickRight ] = joyx [ 0 ] > 0 ? ( float ) joyx [ 0 ] / 128 : 0.f ;
2019-02-21 11:46:00 +00:00
if ( io . NavInputs [ ImGuiNavInput_LStickRight ] < 0.1f )
2019-02-07 15:59:24 +00:00
io . NavInputs [ ImGuiNavInput_LStickRight ] = 0.f ;
io . NavInputs [ ImGuiNavInput_LStickUp ] = joyy [ 0 ] < 0 ? - ( float ) joyy [ 0 ] / 128.f : 0.f ;
2019-02-21 11:46:00 +00:00
if ( io . NavInputs [ ImGuiNavInput_LStickUp ] < 0.1f )
2019-02-07 15:59:24 +00:00
io . NavInputs [ ImGuiNavInput_LStickUp ] = 0.f ;
io . NavInputs [ ImGuiNavInput_LStickDown ] = joyy [ 0 ] > 0 ? ( float ) joyy [ 0 ] / 128.f : 0.f ;
2019-02-21 11:46:00 +00:00
if ( io . NavInputs [ ImGuiNavInput_LStickDown ] < 0.1f )
2019-02-07 15:59:24 +00:00
io . NavInputs [ ImGuiNavInput_LStickDown ] = 0.f ;
2019-02-25 16:52:53 +00:00
if ( KeyboardDevice : : GetInstance ( ) ! = NULL )
{
2020-03-12 15:09:05 +00:00
const std : : string input_text = KeyboardDevice : : GetInstance ( ) - > get_character_input ( ) ;
2019-02-25 16:52:53 +00:00
if ( io . WantCaptureKeyboard )
2020-03-12 15:09:05 +00:00
{
for ( const u8 b : input_text )
// Cheap ISO Latin-1 to UTF-8 conversion
if ( b < 0x80 )
io . AddInputCharacter ( b ) ;
else
io . AddInputCharacter ( ( 0xc2 + ( b > 0xbf ) ) | ( ( b & 0x3f ) + 0x80 ) < < 8 ) ;
}
2019-02-25 16:52:53 +00:00
}
2019-02-06 18:57:13 +00:00
}
2020-03-14 21:46:40 +00:00
#if 0
2020-04-09 09:44:19 +00:00
# include "oslib/timeseries.h"
2020-03-14 21:46:40 +00:00
TimeSeries renderTimes ;
TimeSeries vblankTimes ;
2019-02-06 18:57:13 +00:00
2019-12-25 12:09:54 +00:00
void gui_plot_render_time ( int width , int height )
{
2020-03-14 21:46:40 +00:00
std : : vector < float > v = renderTimes . data ( ) ;
ImGui : : PlotLines ( " Render Times " , v . data ( ) , v . size ( ) , 0 , " " , 0.0 , 1.0 / 30.0 , ImVec2 ( 300 , 50 ) ) ;
ImGui : : Text ( " StdDev: %.1f%% " , renderTimes . stddev ( ) * 100.f / 0.01666666667f ) ;
v = vblankTimes . data ( ) ;
ImGui : : PlotLines ( " VBlank " , v . data ( ) , v . size ( ) , 0 , " " , 0.0 , 1.0 / 30.0 , ImVec2 ( 300 , 50 ) ) ;
ImGui : : Text ( " StdDev: %.1f%% " , vblankTimes . stddev ( ) * 100.f / 0.01666666667f ) ;
2019-02-06 18:57:13 +00:00
}
2020-03-14 21:46:40 +00:00
# endif
2019-02-06 18:57:13 +00:00
// Helper to display a little (?) mark which shows a tooltip when hovered.
static void ShowHelpMarker ( const char * desc )
{
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : PushTextWrapPos ( ImGui : : GetFontSize ( ) * 35.0f ) ;
ImGui : : TextUnformatted ( desc ) ;
ImGui : : PopTextWrapPos ( ) ;
ImGui : : EndTooltip ( ) ;
}
}
void gui_open_settings ( )
{
if ( gui_state = = Closed )
{
gui_state = Commands ;
settings_opening = true ;
2019-02-13 19:29:49 +00:00
HideOSD ( ) ;
2019-02-06 18:57:13 +00:00
}
2019-03-04 23:54:01 +00:00
else if ( gui_state = = VJoyEdit )
{
gui_state = VJoyEditCommands ;
}
2020-04-22 17:11:49 +00:00
else if ( gui_state = = Loading )
{
dc_cancel_load ( ) ;
gui_state = Main ;
}
else if ( gui_state = = Commands )
{
gui_state = Closed ;
dc_resume ( ) ;
}
2019-02-06 18:57:13 +00:00
}
2019-07-13 08:59:20 +00:00
static void gui_start_game ( const std : : string & path )
{
2020-04-09 09:44:19 +00:00
scanner . stop ( ) ;
2020-04-20 16:52:02 +00:00
gui_state = Loading ;
static std : : string path_copy ;
path_copy = path ; // path may be a local var
dc_load_game ( path . empty ( ) ? NULL : path_copy . c_str ( ) ) ;
2019-07-13 08:59:20 +00:00
}
2019-02-06 18:57:13 +00:00
static void gui_display_commands ( )
{
2019-02-25 16:52:53 +00:00
dc_stop ( ) ;
2019-02-06 18:57:13 +00:00
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
2019-10-05 09:50:14 +00:00
if ( ! settings_opening & & settings . pvr . IsOpenGL ( ) )
2019-02-06 18:57:13 +00:00
ImGui_ImplOpenGL3_DrawBackground ( ) ;
2019-04-08 13:54:37 +00:00
if ( ! settings . rend . FloatVMUs )
// If floating VMUs, they are already visible on the background
display_vmus ( ) ;
2019-03-29 16:35:00 +00:00
2019-02-06 18:57:13 +00:00
ImGui : : SetNextWindowPos ( ImVec2 ( screen_width / 2.f , screen_height / 2.f ) , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( 330 * scaling , 0 ) ) ;
2020-04-20 16:52:02 +00:00
ImGui : : Begin ( " ##commands " , NULL , ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize ) ;
2019-02-06 18:57:13 +00:00
ImGui : : Columns ( 2 , " buttons " , false ) ;
if ( ImGui : : Button ( " Load State " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
2020-04-20 16:52:02 +00:00
gui_state = Closed ;
2019-02-06 18:57:13 +00:00
dc_loadstate ( ) ;
}
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Save State " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
2020-04-20 16:52:02 +00:00
gui_state = Closed ;
2019-02-06 18:57:13 +00:00
dc_savestate ( ) ;
}
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Settings " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
gui_state = Settings ;
}
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Resume " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
gui_state = Closed ;
}
ImGui : : NextColumn ( ) ;
2020-01-30 17:59:26 +00:00
const char * disk_label = libGDR_GetDiscType ( ) = = Open ? " Insert Disk " : " Eject Disk " ;
if ( ImGui : : Button ( disk_label , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
2019-02-06 18:57:13 +00:00
{
2020-01-30 17:59:26 +00:00
if ( libGDR_GetDiscType ( ) = = Open )
{
gui_state = SelectDisk ;
}
else
{
DiscOpenLid ( ) ;
gui_state = Closed ;
}
2019-02-06 18:57:13 +00:00
}
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Exit " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
2019-02-25 16:52:53 +00:00
// Exit to main menu
gui_state = Main ;
game_started = false ;
2020-01-30 17:59:26 +00:00
settings . imgread . ImagePath [ 0 ] = ' \0 ' ;
2020-04-14 15:43:11 +00:00
dc_reset ( true ) ;
2019-02-06 18:57:13 +00:00
}
2019-03-13 20:54:04 +00:00
ImGui : : End ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : Render ( ) ;
2019-10-05 09:50:14 +00:00
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) , settings_opening ) ;
2019-02-06 18:57:13 +00:00
settings_opening = false ;
}
2019-07-12 17:18:39 +00:00
const char * maple_device_types [ ] = { " None " , " Sega Controller " , " Light Gun " , " Keyboard " , " Mouse " , " Twin Stick " , " Ascii Stick " } ;
2019-02-12 10:30:24 +00:00
const char * maple_expansion_device_types [ ] = { " None " , " Sega VMU " , " Purupuru " , " Microphone " } ;
static const char * maple_device_name ( MapleDeviceType type )
{
switch ( type )
{
case MDT_SegaController :
return maple_device_types [ 1 ] ;
case MDT_LightGun :
return maple_device_types [ 2 ] ;
case MDT_Keyboard :
return maple_device_types [ 3 ] ;
case MDT_Mouse :
return maple_device_types [ 4 ] ;
2019-07-12 17:18:39 +00:00
case MDT_TwinStick :
return maple_device_types [ 5 ] ;
case MDT_AsciiStick :
return maple_device_types [ 6 ] ;
2019-02-12 10:30:24 +00:00
case MDT_None :
default :
return maple_device_types [ 0 ] ;
}
}
static MapleDeviceType maple_device_type_from_index ( int idx )
{
switch ( idx )
{
case 1 :
return MDT_SegaController ;
case 2 :
return MDT_LightGun ;
case 3 :
return MDT_Keyboard ;
case 4 :
return MDT_Mouse ;
2019-07-12 17:18:39 +00:00
case 5 :
return MDT_TwinStick ;
case 6 :
return MDT_AsciiStick ;
2019-02-12 10:30:24 +00:00
case 0 :
default :
return MDT_None ;
}
}
static const char * maple_expansion_device_name ( MapleDeviceType type )
{
switch ( type )
{
case MDT_SegaVMU :
return maple_expansion_device_types [ 1 ] ;
case MDT_PurupuruPack :
return maple_expansion_device_types [ 2 ] ;
case MDT_Microphone :
return maple_expansion_device_types [ 3 ] ;
case MDT_None :
default :
return maple_expansion_device_types [ 0 ] ;
}
}
const char * maple_ports [ ] = { " None " , " A " , " B " , " C " , " D " } ;
2020-04-17 15:55:43 +00:00
const DreamcastKey button_keys [ ] = {
DC_BTN_START , DC_BTN_A , DC_BTN_B , DC_BTN_X , DC_BTN_Y , DC_DPAD_UP , DC_DPAD_DOWN , DC_DPAD_LEFT , DC_DPAD_RIGHT ,
2019-09-27 12:15:29 +00:00
EMU_BTN_MENU , EMU_BTN_ESCAPE , EMU_BTN_FFORWARD , EMU_BTN_TRIGGER_LEFT , EMU_BTN_TRIGGER_RIGHT ,
2020-04-04 16:18:36 +00:00
DC_BTN_C , DC_BTN_D , DC_BTN_Z , DC_DPAD2_UP , DC_DPAD2_DOWN , DC_DPAD2_LEFT , DC_DPAD2_RIGHT ,
2020-04-17 15:55:43 +00:00
EMU_BTN_ANA_UP , EMU_BTN_ANA_DOWN , EMU_BTN_ANA_LEFT , EMU_BTN_ANA_RIGHT
} ;
const char * button_names [ ] = {
" Start " , " A " , " B " , " X " , " Y " , " DPad Up " , " DPad Down " , " DPad Left " , " DPad Right " ,
2019-09-27 12:15:29 +00:00
" Menu " , " Exit " , " Fast-forward " , " Left Trigger " , " Right Trigger " ,
2020-04-04 16:18:36 +00:00
" C " , " D " , " Z " , " Right Dpad Up " , " Right DPad Down " , " Right DPad Left " , " Right DPad Right " ,
2020-04-17 15:55:43 +00:00
" Left Stick Up " , " Left Stick Down " , " Left Stick Left " , " Left Stick Right "
} ;
const char * arcade_button_names [ ] = {
" Start " , " Button 1 " , " Button 2 " , " Button 3 " , " Button 4 " , " Up " , " Down " , " Left " , " Right " ,
2020-03-09 18:44:16 +00:00
" Menu " , " Exit " , " Fast-forward " , " N/A " , " N/A " ,
2020-04-17 15:55:43 +00:00
" Service " , " Coin " , " Test " , " Button 5 " , " Button 6 " , " Button 7 " , " Button 8 " , " N/A " , " N/A " , " N/A " , " N/A "
} ;
const DreamcastKey axis_keys [ ] = {
DC_AXIS_X , DC_AXIS_Y , DC_AXIS_LT , DC_AXIS_RT , DC_AXIS_X2 , DC_AXIS_Y2 , EMU_AXIS_DPAD1_X , EMU_AXIS_DPAD1_Y ,
EMU_AXIS_DPAD2_X , EMU_AXIS_DPAD2_Y , EMU_AXIS_BTN_START , EMU_AXIS_BTN_A , EMU_AXIS_BTN_B , EMU_AXIS_BTN_X , EMU_AXIS_BTN_Y ,
EMU_AXIS_BTN_C , EMU_AXIS_BTN_D , EMU_AXIS_BTN_Z , EMU_AXIS_DPAD2_UP , EMU_AXIS_DPAD2_DOWN , EMU_AXIS_DPAD2_LEFT , EMU_AXIS_DPAD2_RIGHT
} ;
const char * axis_names [ ] = {
" Left Stick X " , " Left Stick Y " , " Left Trigger " , " Right Trigger " , " Right Stick X " , " Right Stick Y " , " DPad X " , " DPad Y " ,
" Right DPad X " , " Right DPad Y " , " Start " , " A " , " B " , " X " , " Y " ,
" C " , " D " , " Z " , " N/A " , " N/A " , " N/A " , " N/A "
} ;
const char * arcade_axis_names [ ] = {
" Left Stick X " , " Left Stick Y " , " Left Trigger " , " Right Trigger " , " Right Stick X " , " Right Stick Y " , " DPad X " , " DPad Y " ,
" Right DPad X " , " Right DPad Y " , " Start " , " Button 1 " , " Button 2 " , " Button 3 " , " Button 4 " ,
" Service " , " Coin " , " Test " , " Button 5 " , " Button 6 " , " Button 7 " , " Button 8 "
} ;
static_assert ( ARRAY_SIZE ( button_keys ) = = ARRAY_SIZE ( button_names ) , " invalid size " ) ;
static_assert ( ARRAY_SIZE ( button_keys ) = = ARRAY_SIZE ( arcade_button_names ) , " invalid size " ) ;
static_assert ( ARRAY_SIZE ( axis_keys ) = = ARRAY_SIZE ( axis_names ) , " invalid size " ) ;
static_assert ( ARRAY_SIZE ( axis_keys ) = = ARRAY_SIZE ( arcade_axis_names ) , " invalid size " ) ;
2019-02-12 10:30:24 +00:00
static MapleDeviceType maple_expansion_device_type_from_index ( int idx )
{
switch ( idx )
{
case 1 :
return MDT_SegaVMU ;
case 2 :
return MDT_PurupuruPack ;
case 3 :
return MDT_Microphone ;
case 0 :
default :
return MDT_None ;
}
}
2019-02-21 13:49:27 +00:00
static std : : shared_ptr < GamepadDevice > mapped_device ;
2019-02-12 10:30:24 +00:00
static u32 mapped_code ;
static double map_start_time ;
2020-03-09 18:44:16 +00:00
static bool arcade_button_mode ;
2019-02-12 10:30:24 +00:00
static void input_detected ( u32 code )
{
mapped_code = code ;
}
static void detect_input_popup ( int index , bool analog )
{
ImVec2 padding = ImVec2 ( 20 * scaling , 20 * scaling ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , padding ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_ItemSpacing , padding ) ;
if ( ImGui : : BeginPopupModal ( analog ? " Map Axis " : " Map Button " , NULL , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove ) )
{
2020-03-09 18:44:16 +00:00
ImGui : : Text ( " Waiting for %s '%s'... " , analog ? " axis " : " button " ,
2020-04-07 00:33:05 +00:00
analog ? arcade_button_mode ? arcade_axis_names [ index ] : axis_names [ index ]
2020-03-09 18:44:16 +00:00
: arcade_button_mode ? arcade_button_names [ index ] : button_names [ index ] ) ;
2019-02-12 10:30:24 +00:00
double now = os_GetSeconds ( ) ;
ImGui : : Text ( " Time out in %d s " , ( int ) ( 5 - ( now - map_start_time ) ) ) ;
2020-03-12 15:09:05 +00:00
if ( mapped_code ! = ( u32 ) - 1 )
2019-02-12 10:30:24 +00:00
{
2020-03-12 15:09:05 +00:00
std : : shared_ptr < InputMapping > input_mapping = mapped_device - > get_input_mapping ( ) ;
2019-02-21 16:57:51 +00:00
if ( input_mapping ! = NULL )
2019-02-12 10:30:24 +00:00
{
2019-02-21 16:57:51 +00:00
if ( analog )
{
u32 previous_mapping = input_mapping - > get_axis_code ( axis_keys [ index ] ) ;
bool inverted = false ;
2020-03-12 15:09:05 +00:00
if ( previous_mapping ! = ( u32 ) - 1 )
2019-02-21 16:57:51 +00:00
inverted = input_mapping - > get_axis_inverted ( previous_mapping ) ;
// FIXME Allow inverted to be set
input_mapping - > set_axis ( axis_keys [ index ] , mapped_code , inverted ) ;
}
else
input_mapping - > set_button ( button_keys [ index ] , mapped_code ) ;
2019-02-12 10:30:24 +00:00
}
2019-02-21 13:49:27 +00:00
mapped_device = NULL ;
2019-02-12 10:30:24 +00:00
ImGui : : CloseCurrentPopup ( ) ;
}
else if ( now - map_start_time > = 5 )
2019-02-21 13:49:27 +00:00
{
mapped_device = NULL ;
2019-02-12 10:30:24 +00:00
ImGui : : CloseCurrentPopup ( ) ;
2019-02-21 13:49:27 +00:00
}
2019-02-12 10:30:24 +00:00
ImGui : : EndPopup ( ) ;
}
ImGui : : PopStyleVar ( 2 ) ;
}
2019-02-21 13:49:27 +00:00
static void controller_mapping_popup ( std : : shared_ptr < GamepadDevice > gamepad )
2019-02-12 16:57:11 +00:00
{
2019-02-17 23:25:06 +00:00
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( screen_width , screen_height ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0 ) ;
2019-02-12 16:57:11 +00:00
if ( ImGui : : BeginPopupModal ( " Controller Mapping " , NULL , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove ) )
{
2019-02-17 23:25:06 +00:00
const float width = screen_width / 2 ;
2019-02-12 16:57:11 +00:00
const float col0_width = ImGui : : CalcTextSize ( " Right DPad Downxxx " ) . x + ImGui : : GetStyle ( ) . FramePadding . x * 2.0f + ImGui : : GetStyle ( ) . ItemSpacing . x ;
const float col1_width = width
- ImGui : : GetStyle ( ) . GrabMinSize
- ( col0_width + ImGui : : GetStyle ( ) . ItemSpacing . x )
- ( ImGui : : CalcTextSize ( " Map " ) . x + ImGui : : GetStyle ( ) . FramePadding . x * 2.0f + ImGui : : GetStyle ( ) . ItemSpacing . x ) ;
2020-03-12 15:09:05 +00:00
std : : shared_ptr < InputMapping > input_mapping = gamepad - > get_input_mapping ( ) ;
2019-02-21 16:57:51 +00:00
if ( input_mapping = = NULL | | ImGui : : Button ( " Done " , ImVec2 ( 100 * scaling , 30 * scaling ) ) )
2019-02-12 16:57:11 +00:00
{
ImGui : : CloseCurrentPopup ( ) ;
gamepad - > save_mapping ( ) ;
}
ImGui : : SetItemDefaultFocus ( ) ;
2020-03-09 18:44:16 +00:00
ImGui : : SameLine ( ImGui : : GetContentRegionAvailWidth ( ) - ImGui : : CalcTextSize ( " Arcade button names " ) . x
- ImGui : : GetStyle ( ) . FramePadding . x * 3.0f - ImGui : : GetStyle ( ) . ItemSpacing . x ) ;
ImGui : : Checkbox ( " Arcade button names " , & arcade_button_mode ) ;
2019-02-12 16:57:11 +00:00
char key_id [ 32 ] ;
ImGui : : BeginGroup ( ) ;
ImGui : : Text ( " Buttons " ) ;
2019-02-17 23:25:06 +00:00
ImGui : : BeginChildFrame ( ImGui : : GetID ( " buttons " ) , ImVec2 ( width , 0 ) , ImGuiWindowFlags_None ) ;
2019-02-12 16:57:11 +00:00
ImGui : : Columns ( 3 , " bindings " , false ) ;
ImGui : : SetColumnWidth ( 0 , col0_width ) ;
ImGui : : SetColumnWidth ( 1 , col1_width ) ;
2020-03-12 15:09:05 +00:00
for ( u32 j = 0 ; j < ARRAY_SIZE ( button_keys ) ; j + + )
2019-02-12 16:57:11 +00:00
{
sprintf ( key_id , " key_id%d " , j ) ;
ImGui : : PushID ( key_id ) ;
2020-03-09 18:44:16 +00:00
ImGui : : Text ( " %s " , arcade_button_mode ? arcade_button_names [ j ] : button_names [ j ] ) ;
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
2019-02-21 16:57:51 +00:00
u32 code = input_mapping - > get_button_code ( button_keys [ j ] ) ;
2020-03-12 15:09:05 +00:00
if ( code ! = ( u32 ) - 1 )
2019-02-12 16:57:11 +00:00
ImGui : : Text ( " %d " , code ) ;
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Map " ) )
{
map_start_time = os_GetSeconds ( ) ;
ImGui : : OpenPopup ( " Map Button " ) ;
mapped_device = gamepad ;
mapped_code = - 1 ;
gamepad - > detect_btn_input ( & input_detected ) ;
}
detect_input_popup ( j , false ) ;
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
ImGui : : EndChildFrame ( ) ;
ImGui : : EndGroup ( ) ;
ImGui : : SameLine ( ) ;
ImGui : : BeginGroup ( ) ;
ImGui : : Text ( " Analog Axes " ) ;
2019-02-17 23:25:06 +00:00
ImGui : : BeginChildFrame ( ImGui : : GetID ( " analog " ) , ImVec2 ( width , 0 ) , ImGuiWindowFlags_None ) ;
2019-02-12 16:57:11 +00:00
ImGui : : Columns ( 3 , " bindings " , false ) ;
ImGui : : SetColumnWidth ( 0 , col0_width ) ;
ImGui : : SetColumnWidth ( 1 , col1_width ) ;
2020-03-12 15:09:05 +00:00
for ( u32 j = 0 ; j < ARRAY_SIZE ( axis_keys ) ; j + + )
2019-02-12 16:57:11 +00:00
{
sprintf ( key_id , " axis_id%d " , j ) ;
ImGui : : PushID ( key_id ) ;
2020-04-07 00:33:05 +00:00
ImGui : : Text ( " %s " , arcade_button_mode ? arcade_axis_names [ j ] : axis_names [ j ] ) ;
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
2019-02-21 16:57:51 +00:00
u32 code = input_mapping - > get_axis_code ( axis_keys [ j ] ) ;
2020-03-12 15:09:05 +00:00
if ( code ! = ( u32 ) - 1 )
2019-02-12 16:57:11 +00:00
ImGui : : Text ( " %d " , code ) ;
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Map " ) )
{
map_start_time = os_GetSeconds ( ) ;
ImGui : : OpenPopup ( " Map Axis " ) ;
mapped_device = gamepad ;
mapped_code = - 1 ;
gamepad - > detect_axis_input ( & input_detected ) ;
}
detect_input_popup ( j , true ) ;
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
ImGui : : EndChildFrame ( ) ;
ImGui : : EndGroup ( ) ;
ImGui : : EndPopup ( ) ;
}
2019-02-17 23:25:06 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-12 16:57:11 +00:00
}
2019-02-25 16:52:53 +00:00
2019-03-04 23:54:01 +00:00
static void error_popup ( )
{
if ( ! error_msg . empty ( ) )
{
2020-04-20 16:52:02 +00:00
ImGui : : OpenPopup ( " Error " ) ;
2019-03-04 23:54:01 +00:00
if ( ImGui : : BeginPopupModal ( " Error " , NULL , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove ) )
{
ImGui : : PushTextWrapPos ( ImGui : : GetCursorPos ( ) . x + 400.f * scaling ) ;
2019-03-13 20:54:04 +00:00
ImGui : : TextWrapped ( " %s " , error_msg . c_str ( ) ) ;
2019-03-04 23:54:01 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 16 * scaling , 3 * scaling ) ) ;
float currentwidth = ImGui : : GetContentRegionAvailWidth ( ) ;
ImGui : : SetCursorPosX ( ( currentwidth - 80.f * scaling ) / 2.f + ImGui : : GetStyle ( ) . WindowPadding . x ) ;
if ( ImGui : : Button ( " OK " , ImVec2 ( 80.f * scaling , 0.f ) ) )
{
error_msg . clear ( ) ;
ImGui : : CloseCurrentPopup ( ) ;
}
ImGui : : SetItemDefaultFocus ( ) ;
ImGui : : PopStyleVar ( ) ;
ImGui : : EndPopup ( ) ;
}
}
}
2019-02-25 16:52:53 +00:00
void directory_selected_callback ( bool cancelled , std : : string selection )
{
if ( ! cancelled )
{
settings . dreamcast . ContentPath . push_back ( selection ) ;
2020-04-09 09:44:19 +00:00
scanner . refresh ( ) ;
2019-02-25 16:52:53 +00:00
}
}
2019-02-06 18:57:13 +00:00
static void gui_display_settings ( )
{
2019-04-08 13:54:37 +00:00
static bool maple_devices_changed ;
2019-02-06 18:57:13 +00:00
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
int dynarec_enabled = settings . dynarec . Enable ;
2019-10-23 17:23:19 +00:00
int pvr_rend = settings . pvr . rend ;
2019-11-13 19:08:14 +00:00
bool vulkan = pvr_rend = = 4 | | pvr_rend = = 5 ;
2019-02-20 22:22:58 +00:00
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( screen_width , screen_height ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0 ) ;
2019-02-06 18:57:13 +00:00
ImGui : : Begin ( " Settings " , NULL , /*ImGuiWindowFlags_AlwaysAutoResize |*/ ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse ) ;
2019-02-16 13:25:54 +00:00
ImVec2 normal_padding = ImGui : : GetStyle ( ) . FramePadding ;
2019-02-06 18:57:13 +00:00
if ( ImGui : : Button ( " Done " , ImVec2 ( 100 * scaling , 30 * scaling ) ) )
{
2019-02-25 16:52:53 +00:00
if ( game_started )
gui_state = Commands ;
else
gui_state = Main ;
2019-04-08 13:54:37 +00:00
if ( maple_devices_changed )
{
maple_devices_changed = false ;
2019-07-09 21:52:19 +00:00
if ( game_started & & settings . platform . system = = DC_PLATFORM_DREAMCAST )
{
maple_ReconnectDevices ( ) ;
reset_vmus ( ) ;
}
2019-04-08 13:54:37 +00:00
}
2019-02-06 18:57:13 +00:00
SaveSettings ( ) ;
}
2019-02-25 16:52:53 +00:00
if ( game_started )
{
ImGui : : SameLine ( ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 16 * scaling , normal_padding . y ) ) ;
if ( cfgHasGameSpecificConfig ( ) )
{
if ( ImGui : : Button ( " Delete Game Config " , ImVec2 ( 0 , 30 * scaling ) ) )
{
cfgDeleteGameSpecificConfig ( ) ;
InitSettings ( ) ;
LoadSettings ( false ) ;
}
}
else
{
if ( ImGui : : Button ( " Make Game Config " , ImVec2 ( 0 , 30 * scaling ) ) )
cfgMakeGameSpecificConfig ( ) ;
}
ImGui : : PopStyleVar ( ) ;
}
2019-02-16 13:25:54 +00:00
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 16 * scaling , 6 * scaling ) ) ; // from 4, 3
2019-02-06 18:57:13 +00:00
if ( ImGui : : BeginTabBar ( " settings " , ImGuiTabBarFlags_NoTooltip ) )
{
if ( ImGui : : BeginTabItem ( " General " ) )
{
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
2019-02-06 18:57:13 +00:00
const char * languages [ ] = { " Japanese " , " English " , " German " , " French " , " Spanish " , " Italian " , " Default " } ;
if ( ImGui : : BeginCombo ( " Language " , languages [ settings . dreamcast . language ] , ImGuiComboFlags_None ) )
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( languages ) ; i + + )
{
2020-03-12 15:09:05 +00:00
bool is_selected = ( int ) settings . dreamcast . language = = i ;
2019-02-06 18:57:13 +00:00
if ( ImGui : : Selectable ( languages [ i ] , & is_selected ) )
settings . dreamcast . language = i ;
2019-02-09 20:20:03 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
2019-02-06 18:57:13 +00:00
}
ImGui : : EndCombo ( ) ;
}
ImGui : : SameLine ( ) ;
2019-02-09 21:15:08 +00:00
ShowHelpMarker ( " The language as configured in the Dreamcast BIOS " ) ;
2019-02-06 18:57:13 +00:00
const char * broadcast [ ] = { " NTSC " , " PAL " , " PAL/M " , " PAL/N " , " Default " } ;
if ( ImGui : : BeginCombo ( " Broadcast " , broadcast [ settings . dreamcast . broadcast ] , ImGuiComboFlags_None ) )
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( broadcast ) ; i + + )
{
2020-03-12 15:09:05 +00:00
bool is_selected = ( int ) settings . dreamcast . broadcast = = i ;
2019-02-06 18:57:13 +00:00
if ( ImGui : : Selectable ( broadcast [ i ] , & is_selected ) )
settings . dreamcast . broadcast = i ;
2019-02-09 20:20:03 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
2019-02-06 18:57:13 +00:00
}
ImGui : : EndCombo ( ) ;
}
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " TV broadcasting standard for non-VGA modes " ) ;
2019-02-06 18:57:13 +00:00
const char * region [ ] = { " Japan " , " USA " , " Europe " , " Default " } ;
if ( ImGui : : BeginCombo ( " Region " , region [ settings . dreamcast . region ] , ImGuiComboFlags_None ) )
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( region ) ; i + + )
{
2020-03-12 15:09:05 +00:00
bool is_selected = ( int ) settings . dreamcast . region = = i ;
2019-02-06 18:57:13 +00:00
if ( ImGui : : Selectable ( region [ i ] , & is_selected ) )
settings . dreamcast . region = i ;
2019-02-09 20:20:03 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
2019-02-06 18:57:13 +00:00
}
ImGui : : EndCombo ( ) ;
}
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " BIOS region " ) ;
2019-02-06 18:57:13 +00:00
2019-02-09 20:20:03 +00:00
const char * cable [ ] = { " VGA " , " RGB Component " , " TV Composite " } ;
if ( ImGui : : BeginCombo ( " Cable " , cable [ settings . dreamcast . cable = = 0 ? 0 : settings . dreamcast . cable - 1 ] , ImGuiComboFlags_None ) )
2019-02-06 18:57:13 +00:00
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( cable ) ; i + + )
{
2020-03-12 15:09:05 +00:00
bool is_selected = i = = 0 ? ( int ) settings . dreamcast . cable < = 1 : ( int ) settings . dreamcast . cable - 1 = = i ;
2019-02-06 18:57:13 +00:00
if ( ImGui : : Selectable ( cable [ i ] , & is_selected ) )
2019-02-09 20:20:03 +00:00
settings . dreamcast . cable = i = = 0 ? 0 : i + 1 ;
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
2019-02-06 18:57:13 +00:00
}
ImGui : : EndCombo ( ) ;
}
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Video connection type " ) ;
2019-02-06 18:57:13 +00:00
2019-02-25 16:52:53 +00:00
std : : vector < const char * > paths ;
2019-06-08 11:04:35 +00:00
for ( auto & path : settings . dreamcast . ContentPath )
2019-02-25 16:52:53 +00:00
paths . push_back ( path . c_str ( ) ) ;
ImVec2 size ;
size . x = 0.0f ;
size . y = ( ImGui : : GetTextLineHeightWithSpacing ( ) + ImGui : : GetStyle ( ) . FramePadding . y * 2.f )
* ( settings . dreamcast . ContentPath . size ( ) + 1 ) ; //+ ImGui::GetStyle().FramePadding.y * 2.f;
if ( ImGui : : ListBoxHeader ( " Content Location " , size ) )
{
int to_delete = - 1 ;
2020-03-12 15:09:05 +00:00
for ( u32 i = 0 ; i < settings . dreamcast . ContentPath . size ( ) ; i + + )
2019-02-25 16:52:53 +00:00
{
ImGui : : PushID ( settings . dreamcast . ContentPath [ i ] . c_str ( ) ) ;
ImGui : : AlignTextToFramePadding ( ) ;
ImGui : : Text ( " %s " , settings . dreamcast . ContentPath [ i ] . c_str ( ) ) ;
ImGui : : SameLine ( ImGui : : GetContentRegionAvailWidth ( ) - ImGui : : CalcTextSize ( " X " ) . x - ImGui : : GetStyle ( ) . FramePadding . x ) ;
if ( ImGui : : Button ( " X " ) )
to_delete = i ;
ImGui : : PopID ( ) ;
}
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 24 * scaling , 3 * scaling ) ) ;
2020-03-12 15:09:05 +00:00
if ( ImGui : : Button ( " Add " ) )
ImGui : : OpenPopup ( " Select Directory " ) ;
select_directory_popup ( " Select Directory " , scaling , & directory_selected_callback ) ;
ImGui : : PopStyleVar ( ) ;
2019-02-25 16:52:53 +00:00
ImGui : : ListBoxFooter ( ) ;
if ( to_delete > = 0 )
{
settings . dreamcast . ContentPath . erase ( settings . dreamcast . ContentPath . begin ( ) + to_delete ) ;
2020-04-09 09:44:19 +00:00
scanner . refresh ( ) ;
2019-02-25 16:52:53 +00:00
}
}
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " The directories where your games are stored " ) ;
2019-03-05 11:45:11 +00:00
if ( ImGui : : ListBoxHeader ( " Home Directory " , 1 ) )
{
ImGui : : AlignTextToFramePadding ( ) ;
ImGui : : Text ( " %s " , get_writable_config_path ( " " ) . c_str ( ) ) ;
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2019-03-05 11:45:11 +00:00
ImGui : : SameLine ( ImGui : : GetContentRegionAvailWidth ( ) - ImGui : : CalcTextSize ( " Change " ) . x - ImGui : : GetStyle ( ) . FramePadding . x ) ;
if ( ImGui : : Button ( " Change " ) )
gui_state = Onboarding ;
# endif
ImGui : : ListBoxFooter ( ) ;
}
ImGui : : SameLine ( ) ;
2020-04-09 09:44:19 +00:00
ShowHelpMarker ( " The directory where reicast saves configuration files and VMUs. BIOS files should be in a subfolder named \" data \" " ) ;
2019-09-10 19:56:58 +00:00
if ( ImGui : : Checkbox ( " Hide Legacy Naomi Roms " , & settings . dreamcast . HideLegacyNaomiRoms ) )
2020-04-09 09:44:19 +00:00
scanner . refresh ( ) ;
2019-09-10 19:56:58 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Hide .bin, .dat and .lst files from the content browser " ) ;
2019-02-25 16:52:53 +00:00
2019-02-09 20:20:03 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : EndTabItem ( ) ;
}
if ( ImGui : : BeginTabItem ( " Controls " ) )
{
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
2019-02-12 10:30:24 +00:00
if ( ImGui : : CollapsingHeader ( " Dreamcast Devices " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
for ( int bus = 0 ; bus < MAPLE_PORTS ; bus + + )
{
ImGui : : Text ( " Device %c " , bus + ' A ' ) ;
ImGui : : SameLine ( ) ;
char device_name [ 32 ] ;
sprintf ( device_name , " ##device%d " , bus ) ;
float w = ImGui : : CalcItemWidth ( ) / 3 ;
ImGui : : PushItemWidth ( w ) ;
if ( ImGui : : BeginCombo ( device_name , maple_device_name ( ( MapleDeviceType ) settings . input . maple_devices [ bus ] ) , ImGuiComboFlags_None ) )
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( maple_device_types ) ; i + + )
{
bool is_selected = settings . input . maple_devices [ bus ] = = maple_device_type_from_index ( i ) ;
if ( ImGui : : Selectable ( maple_device_types [ i ] , & is_selected ) )
2019-04-08 13:54:37 +00:00
{
2019-02-12 10:30:24 +00:00
settings . input . maple_devices [ bus ] = maple_device_type_from_index ( i ) ;
2019-04-08 13:54:37 +00:00
maple_devices_changed = true ;
}
2019-02-12 10:30:24 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
}
ImGui : : EndCombo ( ) ;
}
2019-07-12 17:18:39 +00:00
int port_count = settings . input . maple_devices [ bus ] = = MDT_SegaController ? 2
: settings . input . maple_devices [ bus ] = = MDT_LightGun | | settings . input . maple_devices [ bus ] = = MDT_TwinStick | | settings . input . maple_devices [ bus ] = = MDT_AsciiStick ? 1
: 0 ;
2019-02-12 10:30:24 +00:00
for ( int port = 0 ; port < port_count ; port + + )
{
ImGui : : SameLine ( ) ;
sprintf ( device_name , " ##device%d.%d " , bus , port + 1 ) ;
ImGui : : PushID ( device_name ) ;
if ( ImGui : : BeginCombo ( device_name , maple_expansion_device_name ( ( MapleDeviceType ) settings . input . maple_expansion_devices [ bus ] [ port ] ) , ImGuiComboFlags_None ) )
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( maple_expansion_device_types ) ; i + + )
{
bool is_selected = settings . input . maple_expansion_devices [ bus ] [ port ] = = maple_expansion_device_type_from_index ( i ) ;
if ( ImGui : : Selectable ( maple_expansion_device_types [ i ] , & is_selected ) )
2019-04-08 13:54:37 +00:00
{
2019-02-12 10:30:24 +00:00
settings . input . maple_expansion_devices [ bus ] [ port ] = maple_expansion_device_type_from_index ( i ) ;
2019-04-08 13:54:37 +00:00
maple_devices_changed = true ;
}
2019-02-12 10:30:24 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
}
ImGui : : EndCombo ( ) ;
}
ImGui : : PopID ( ) ;
}
ImGui : : PopItemWidth ( ) ;
}
ImGui : : Spacing ( ) ;
}
if ( ImGui : : CollapsingHeader ( " Physical Devices " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : Columns ( 4 , " renderers " , false ) ;
ImGui : : Text ( " System " ) ;
ImGui : : SetColumnWidth ( - 1 , ImGui : : CalcTextSize ( " System " ) . x + ImGui : : GetStyle ( ) . FramePadding . x * 2.0f + ImGui : : GetStyle ( ) . ItemSpacing . x ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Name " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Port " ) ;
ImGui : : SetColumnWidth ( - 1 , ImGui : : CalcTextSize ( " None " ) . x * 1.6f + ImGui : : GetStyle ( ) . FramePadding . x * 2.0f + ImGui : : GetFrameHeight ( )
+ ImGui : : GetStyle ( ) . ItemInnerSpacing . x + ImGui : : GetStyle ( ) . ItemSpacing . x ) ;
ImGui : : NextColumn ( ) ;
ImGui : : NextColumn ( ) ;
for ( int i = 0 ; i < GamepadDevice : : GetGamepadCount ( ) ; i + + )
{
2019-02-21 13:49:27 +00:00
std : : shared_ptr < GamepadDevice > gamepad = GamepadDevice : : GetGamepad ( i ) ;
if ( ! gamepad )
2019-02-12 10:30:24 +00:00
continue ;
2019-02-12 14:56:44 +00:00
ImGui : : Text ( " %s " , gamepad - > api_name ( ) . c_str ( ) ) ;
2019-02-12 10:30:24 +00:00
ImGui : : NextColumn ( ) ;
2019-02-12 14:56:44 +00:00
ImGui : : Text ( " %s " , gamepad - > name ( ) . c_str ( ) ) ;
2019-02-12 10:30:24 +00:00
ImGui : : NextColumn ( ) ;
char port_name [ 32 ] ;
sprintf ( port_name , " ##mapleport%d " , i ) ;
ImGui : : PushID ( port_name ) ;
if ( ImGui : : BeginCombo ( port_name , maple_ports [ gamepad - > maple_port ( ) + 1 ] ) )
{
for ( int j = - 1 ; j < MAPLE_PORTS ; j + + )
{
bool is_selected = gamepad - > maple_port ( ) = = j ;
if ( ImGui : : Selectable ( maple_ports [ j + 1 ] , & is_selected ) )
gamepad - > set_maple_port ( j ) ;
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
}
ImGui : : EndCombo ( ) ;
}
ImGui : : NextColumn ( ) ;
2019-02-13 19:29:49 +00:00
if ( gamepad - > remappable ( ) & & ImGui : : Button ( " Map " ) )
2019-02-12 10:30:24 +00:00
ImGui : : OpenPopup ( " Controller Mapping " ) ;
2019-02-12 16:57:11 +00:00
controller_mapping_popup ( gamepad ) ;
2019-02-12 10:30:24 +00:00
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2019-03-04 23:54:01 +00:00
if ( gamepad - > is_virtual_gamepad ( ) )
{
if ( ImGui : : Button ( " Edit " ) )
{
vjoy_start_editing ( ) ;
gui_state = VJoyEdit ;
}
ImGui : : SameLine ( ) ;
ImGui : : SliderInt ( " Haptic " , & settings . input . VirtualGamepadVibration , 0 , 60 ) ;
}
# endif
2019-02-12 10:30:24 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
}
ImGui : : Columns ( 1 , NULL , false ) ;
ImGui : : Spacing ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : SliderInt ( " Mouse sensitivity " , ( int * ) & settings . input . MouseSensitivity , 1 , 500 ) ;
2019-02-12 10:30:24 +00:00
2019-02-09 20:20:03 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : EndTabItem ( ) ;
}
if ( ImGui : : BeginTabItem ( " Video " ) )
{
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
2019-05-17 18:05:01 +00:00
# if HOST_OS != OS_DARWIN
2020-01-31 17:33:16 +00:00
bool has_per_pixel = false ;
2019-11-13 19:08:14 +00:00
if ( ! vulkan )
has_per_pixel = ! theGLContext . IsGLES ( ) & & theGLContext . GetMajorVersion ( ) > = 4 ;
2020-01-31 17:33:16 +00:00
# ifdef USE_VULKAN
2019-11-13 19:08:14 +00:00
else
has_per_pixel = VulkanContext : : Instance ( ) - > SupportsFragmentShaderStoresAndAtomics ( ) ;
2020-01-31 17:33:16 +00:00
# endif
2019-05-17 18:05:01 +00:00
# else
bool has_per_pixel = false ;
# endif
2019-05-17 17:48:25 +00:00
if ( ImGui : : CollapsingHeader ( " Transparent Sorting " , ImGuiTreeNodeFlags_DefaultOpen ) )
2019-02-09 20:20:03 +00:00
{
2019-11-13 19:08:14 +00:00
int renderer = ( pvr_rend = = 3 | | pvr_rend = = 5 ) ? 2 : settings . rend . PerStripSorting ? 1 : 0 ;
2019-05-17 17:48:25 +00:00
ImGui : : Columns ( has_per_pixel ? 3 : 2 , " renderers " , false ) ;
ImGui : : RadioButton ( " Per Triangle " , & renderer , 0 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Sort transparent polygons per triangle. Fast but may produce graphical glitches " ) ;
2019-05-17 17:48:25 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : RadioButton ( " Per Strip " , & renderer , 1 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
2019-05-17 17:48:25 +00:00
ShowHelpMarker ( " Sort transparent polygons per strip. Faster but may produce graphical glitches " ) ;
if ( has_per_pixel )
{
ImGui : : NextColumn ( ) ;
ImGui : : RadioButton ( " Per Pixel " , & renderer , 2 ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Sort transparent polygons per pixel. Slower but accurate " ) ;
}
2019-02-09 20:20:03 +00:00
ImGui : : Columns ( 1 , NULL , false ) ;
2019-05-17 17:48:25 +00:00
switch ( renderer )
{
case 0 :
2019-11-13 19:08:14 +00:00
if ( ! vulkan )
pvr_rend = 0 ; // regular Open GL
else
pvr_rend = 4 ; // regular Vulkan
2019-05-17 17:48:25 +00:00
settings . rend . PerStripSorting = false ;
break ;
case 1 :
2019-11-13 19:08:14 +00:00
if ( ! vulkan )
2019-10-23 17:23:19 +00:00
pvr_rend = 0 ;
2019-11-13 19:08:14 +00:00
else
pvr_rend = 4 ;
2019-05-17 17:48:25 +00:00
settings . rend . PerStripSorting = true ;
break ;
case 2 :
2019-11-13 19:08:14 +00:00
if ( ! vulkan )
pvr_rend = 3 ;
else
pvr_rend = 5 ;
2019-05-17 17:48:25 +00:00
break ;
}
2019-02-09 20:20:03 +00:00
}
if ( ImGui : : CollapsingHeader ( " Rendering Options " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : Checkbox ( " Synchronous Rendering " , & settings . pvr . SynchronousRender ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Reduce frame skipping by pausing the CPU when possible. Recommended for most platforms " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Clipping " , & settings . rend . Clipping ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Enable clipping. May produce graphical errors when disabled " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Shadows " , & settings . rend . ModifierVolumes ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Enable modifier volumes, usually used for shadows " ) ;
2019-04-04 18:05:13 +00:00
ImGui : : Checkbox ( " Fog " , & settings . rend . Fog ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Enable fog effects " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Widescreen " , & settings . rend . WideScreen ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas " ) ;
2019-09-24 21:59:36 +00:00
ImGui : : Checkbox ( " Widescreen Game Cheats " , & settings . rend . WidescreenGameHacks ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Modify the game so that it displays in 16:9 anamorphic format and use horizontal screen stretching. Only some games are supported. " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Show FPS Counter " , & settings . rend . ShowFPS ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Show on-screen frame/sec counter " ) ;
2019-09-10 19:56:58 +00:00
ImGui : : Checkbox ( " Show VMU In-game " , & settings . rend . FloatVMUs ) ;
2019-04-08 13:54:37 +00:00
ImGui : : SameLine ( ) ;
2019-09-10 19:56:58 +00:00
ShowHelpMarker ( " Show the VMU LCD screens while in-game " ) ;
ImGui : : Checkbox ( " Rotate Screen 90° " , & settings . rend . Rotate90 ) ;
2019-04-09 13:18:48 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Rotate the screen 90° counterclockwise " ) ;
2019-09-09 12:58:53 +00:00
ImGui : : Checkbox ( " Delay Frame Swapping " , & settings . rend . DelayFrameSwapping ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Useful to avoid flashing screen or glitchy videos. Not recommended on slow platforms " ) ;
2019-10-15 14:52:02 +00:00
ImGui : : Checkbox ( " Use Vulkan Renderer " , & vulkan ) ;
ImGui : : SameLine ( ) ;
2020-01-31 17:33:16 +00:00
ShowHelpMarker ( " Use Vulkan instead of Open GL/GLES " ) ;
2020-01-29 19:26:09 +00:00
2020-03-29 17:29:14 +00:00
const std : : map < int , const char * > scalings {
2020-01-31 17:33:16 +00:00
{ 10 , " 0.1 " } , { 20 , " 0.2 " } , { 30 , " 0.3 " } , { 40 , " 0.4 " } ,
{ 50 , " 0.5 " } , { 60 , " 0.6 " } , { 70 , " 0.7 " } , { 80 , " 0.8 " } , { 90 , " 0.9 " } ,
{ 100 , " 1.0 (Host native) " } , { 200 , " 2.0 (2x SSAA) " } , { 300 , " 3.0 (3x SSAA) " } ,
{ 400 , " 4.0 (4x SSAA) " } , { 600 , " 6.0 (6x SSAA) " } , { 800 , " 8.0 (8x SSAA) " }
2020-01-29 19:26:09 +00:00
} ;
2020-01-31 17:33:16 +00:00
if ( scalings . count ( settings . rend . ScreenScaling ) = = 0 )
2020-01-29 19:26:09 +00:00
settings . rend . ScreenScaling = 100 ;
auto scalings_it = scalings . find ( settings . rend . ScreenScaling ) ;
ImGuiStyle & scaling_style = ImGui : : GetStyle ( ) ;
float scaling_spacing = scaling_style . ItemInnerSpacing . x ;
ImGui : : PushItemWidth ( ImGui : : CalcItemWidth ( ) - scaling_spacing * 2.0f - ImGui : : GetFrameHeight ( ) * 2.0f ) ;
if ( ImGui : : BeginCombo ( " ##Scaling " , scalings . at ( settings . rend . ScreenScaling ) , ImGuiComboFlags_NoArrowButton ) )
{
2020-01-31 17:33:16 +00:00
for ( const auto & kv : scalings )
{
2020-01-29 19:26:09 +00:00
bool is_selected = ( kv . first = = settings . rend . ScreenScaling ) ;
if ( ImGui : : Selectable ( kv . second , is_selected ) )
settings . rend . ScreenScaling = kv . first ;
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
}
ImGui : : EndCombo ( ) ;
}
ImGui : : PopItemWidth ( ) ;
ImGui : : SameLine ( 0 , scaling_spacing ) ;
if ( ImGui : : ArrowButton ( " ##Decrease Scaling " , ImGuiDir_Left ) )
{
2020-01-31 17:33:16 +00:00
if ( scalings_it ! = scalings . begin ( ) )
2020-01-29 19:26:09 +00:00
settings . rend . ScreenScaling = ( - - scalings_it ) - > first ;
}
ImGui : : SameLine ( 0 , scaling_spacing ) ;
if ( ImGui : : ArrowButton ( " ##Increase Scaling " , ImGuiDir_Right ) )
{
2020-01-31 17:33:16 +00:00
if ( scalings_it ! = ( - - scalings . end ( ) ) )
2020-01-29 19:26:09 +00:00
settings . rend . ScreenScaling = ( + + scalings_it ) - > first ;
}
ImGui : : SameLine ( 0 , scaling_style . ItemInnerSpacing . x ) ;
ImGui : : Text ( " Scaling (SSAA) " ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Downscaling/Upscaling factor relative to native screen resolution. Higher is better but more demanding " ) ;
2019-04-07 22:21:06 +00:00
ImGui : : SliderInt ( " Horizontal Stretching " , ( int * ) & settings . rend . ScreenStretching , 100 , 150 ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Stretch the screen horizontally " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : SliderInt ( " Frame Skipping " , ( int * ) & settings . pvr . ta_skip , 0 , 6 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Number of frames to skip between two actually rendered frames " ) ;
2019-02-09 20:20:03 +00:00
}
if ( ImGui : : CollapsingHeader ( " Render to Texture " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : Checkbox ( " Copy to VRAM " , & settings . rend . RenderToTextureBuffer ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Copy rendered-to textures back to VRAM. Slower but accurate " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : SliderInt ( " Render to Texture Upscaling " , ( int * ) & settings . rend . RenderToTextureUpscale , 1 , 8 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Upscale rendered-to textures. Should be the same as the screen or window upscale ratio, or lower for slow platforms " ) ;
2019-02-09 20:20:03 +00:00
}
if ( ImGui : : CollapsingHeader ( " Texture Upscaling " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : SliderInt ( " Texture Upscaling " , ( int * ) & settings . rend . TextureUpscale , 1 , 8 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
2020-04-09 09:44:19 +00:00
ShowHelpMarker ( " Upscale textures with the xBRZ algorithm. Only on fast platforms and for certain 2D games " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : SliderInt ( " Upscaled Texture Max Size " , ( int * ) & settings . rend . MaxFilteredTextureSize , 8 , 1024 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Textures larger than this dimension squared will not be upscaled " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : SliderInt ( " Max Threads " , ( int * ) & settings . pvr . MaxThreads , 1 , 8 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Maximum number of threads to use for texture upscaling. Recommended: number of physical cores minus one " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Load Custom Textures " , & settings . rend . CustomTextures ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Load custom/high-res textures from data/textures/<game id> " ) ;
2019-02-09 20:20:03 +00:00
}
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : EndTabItem ( ) ;
}
if ( ImGui : : BeginTabItem ( " Audio " ) )
{
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
ImGui : : Checkbox ( " Disable Sound " , & settings . aica . NoSound ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Disable the emulator sound output " ) ;
2019-05-17 15:01:20 +00:00
ImGui : : Checkbox ( " Enable DSP " , & settings . aica . DSPEnabled ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
2020-04-09 09:44:19 +00:00
ShowHelpMarker ( " Enable the Dreamcast Digital Sound Processor. Only recommended on fast platforms " ) ;
2020-02-25 11:52:21 +00:00
ImGui : : Checkbox ( " Limit Emulator Speed " , & settings . aica . LimitFPS ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Whether to limit the emulator speed using the audio output. Recommended " ) ;
2020-03-14 21:46:40 +00:00
int latency = ( int ) roundf ( settings . aica . BufferSize * 1000.f / 44100.f ) ;
ImGui : : SliderInt ( " Latency " , & latency , 12 , 512 , " %d ms " ) ;
settings . aica . BufferSize = ( int ) roundf ( latency * 44100.f / 1000.f ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Sets the maximum audio latency. Not supported by all audio drivers. " ) ;
2019-05-02 16:41:45 +00:00
2020-03-14 21:46:40 +00:00
audiobackend_t * backend = nullptr ;
2019-04-05 20:22:46 +00:00
std : : string backend_name = settings . audio . backend ;
2020-03-14 21:46:40 +00:00
if ( backend_name ! = " auto " )
2019-04-05 20:22:46 +00:00
{
backend = GetAudioBackend ( settings . audio . backend ) ;
if ( backend ! = NULL )
backend_name = backend - > slug ;
}
2019-04-24 19:41:38 +00:00
audiobackend_t * current_backend = backend ;
2019-05-20 17:12:28 +00:00
if ( ImGui : : BeginCombo ( " Audio Driver " , backend_name . c_str ( ) , ImGuiComboFlags_None ) )
2019-04-05 20:22:46 +00:00
{
bool is_selected = ( settings . audio . backend = = " auto " ) ;
2019-05-20 17:12:28 +00:00
if ( ImGui : : Selectable ( " auto - Automatic driver selection " , & is_selected ) )
2019-04-05 20:22:46 +00:00
settings . audio . backend = " auto " ;
2020-03-12 15:09:05 +00:00
for ( u32 i = 0 ; i < GetAudioBackendCount ( ) ; i + + )
2019-04-05 20:22:46 +00:00
{
2019-04-24 19:41:38 +00:00
backend = GetAudioBackend ( i ) ;
2019-04-05 20:22:46 +00:00
is_selected = ( settings . audio . backend = = backend - > slug ) ;
2019-04-24 19:41:38 +00:00
if ( is_selected )
current_backend = backend ;
2019-05-20 17:12:28 +00:00
if ( ImGui : : Selectable ( ( backend - > slug + " - " + backend - > name ) . c_str ( ) , & is_selected ) )
2019-04-05 20:22:46 +00:00
settings . audio . backend = backend - > slug ;
2019-05-20 17:12:28 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
2019-04-05 20:22:46 +00:00
}
ImGui : : EndCombo ( ) ;
}
2019-05-20 17:12:28 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " The audio driver to use " ) ;
2019-04-05 20:22:46 +00:00
2019-04-24 19:41:38 +00:00
if ( current_backend ! = NULL & & current_backend - > get_options ! = NULL )
{
// get backend specific options
int option_count ;
audio_option_t * options = current_backend - > get_options ( & option_count ) ;
// initialize options if not already done
std : : map < std : : string , std : : string > * cfg_entries = & settings . audio . options [ current_backend - > slug ] ;
bool populate_entries = ( cfg_entries - > size ( ) = = 0 ) ;
for ( int o = 0 ; o < option_count ; o + + )
{
std : : string value ;
if ( populate_entries )
{
value = cfgLoadStr ( current_backend - > slug . c_str ( ) , options - > cfg_name . c_str ( ) , " " ) ;
( * cfg_entries ) [ options - > cfg_name ] = value ;
}
value = ( * cfg_entries ) [ options - > cfg_name ] ;
2019-05-02 18:24:49 +00:00
if ( options - > type = = integer )
{
int val = stoi ( value ) ;
ImGui : : SliderInt ( options - > caption . c_str ( ) , & val , options - > min_value , options - > max_value ) ;
2020-03-29 17:29:14 +00:00
( * cfg_entries ) [ options - > cfg_name ] = std : : to_string ( val ) ;
2019-05-02 18:24:49 +00:00
}
else if ( options - > type = = checkbox )
{
bool check = ( value = = " 1 " ) ;
ImGui : : Checkbox ( options - > caption . c_str ( ) , & check ) ;
std : : string cur = check ? " 1 " : " 0 " ;
( * cfg_entries ) [ options - > cfg_name ] = cur ;
}
2019-05-16 10:05:16 +00:00
else if ( options - > type = = : : list )
2019-04-24 19:41:38 +00:00
{
if ( ImGui : : BeginCombo ( options - > caption . c_str ( ) , value . c_str ( ) , ImGuiComboFlags_None ) )
{
bool is_selected = false ;
std : : vector < std : : string > list_items = options - > list_callback ( ) ;
for ( std : : vector < std : : string > : : iterator it = list_items . begin ( ) ; it ! = list_items . end ( ) ; + + it )
{
std : : string cur = ( std : : string ) * it ;
is_selected = ( value = = cur ) ;
if ( ImGui : : Selectable ( cur . c_str ( ) , & is_selected ) )
{
( * cfg_entries ) [ options - > cfg_name ] = cur ;
}
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
}
ImGui : : EndCombo ( ) ;
}
}
2019-05-02 18:24:49 +00:00
else {
2019-07-01 15:17:08 +00:00
WARN_LOG ( RENDERER , " Unknown option " ) ;
2019-05-02 18:24:49 +00:00
}
2019-04-24 19:41:38 +00:00
options + + ;
}
}
2019-02-09 20:20:03 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : EndTabItem ( ) ;
}
if ( ImGui : : BeginTabItem ( " Advanced " ) )
{
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
if ( ImGui : : CollapsingHeader ( " CPU Mode " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : Columns ( 2 , " cpu_modes " , false ) ;
ImGui : : RadioButton ( " Dynarec " , & dynarec_enabled , 1 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Use the dynamic recompiler. Recommended in most cases " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : RadioButton ( " Interpreter " , & dynarec_enabled , 0 ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Use the interpreter. Very slow but may help in case of a dynarec problem " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : Columns ( 1 , NULL , false ) ;
}
if ( ImGui : : CollapsingHeader ( " Dynarec Options " , dynarec_enabled ? ImGuiTreeNodeFlags_DefaultOpen : ImGuiTreeNodeFlags_None ) )
{
ImGui : : Checkbox ( " Safe Mode " , & settings . dynarec . safemode ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Do not optimize integer division. Recommended " ) ;
2019-09-30 13:36:39 +00:00
# if HOST_CPU == CPU_ARM
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Unstable Optimizations " , & settings . dynarec . unstable_opt ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
2019-03-29 18:23:37 +00:00
ShowHelpMarker ( " Enable unsafe optimizations. Will cause crash or environmental disaster " ) ;
2019-09-30 13:36:39 +00:00
# endif
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Idle Skip " , & settings . dynarec . idleskip ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Skip wait loops. Recommended " ) ;
2019-02-09 20:20:03 +00:00
}
2020-04-14 15:43:11 +00:00
if ( ImGui : : CollapsingHeader ( " Network " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
2020-04-19 19:45:15 +00:00
ImGui : : Checkbox ( " Enable " , & settings . network . Enable ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Enable networking for supported Naomi games " ) ;
if ( settings . network . Enable )
{
ImGui : : Checkbox ( " Act as Server " , & settings . network . ActAsServer ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Create a local server for Naomi network games " ) ;
char server_name [ 256 ] ;
strcpy ( server_name , settings . network . server . c_str ( ) ) ;
ImGui : : InputText ( " Server " , server_name , sizeof ( server_name ) , ImGuiInputTextFlags_CharsNoBlank , nullptr , nullptr ) ;
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " The server to connect to. Leave blank to find a server automatically " ) ;
settings . network . server = server_name ;
}
2020-04-14 15:43:11 +00:00
}
2019-02-09 20:20:03 +00:00
if ( ImGui : : CollapsingHeader ( " Other " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
2019-07-30 17:04:51 +00:00
ImGui : : Checkbox ( " HLE BIOS " , & settings . bios . UseReios ) ;
ImGui : : SameLine ( ) ;
2020-04-09 09:44:19 +00:00
ShowHelpMarker ( " Force high-level BIOS emulation " ) ;
2019-08-28 18:47:47 +00:00
ImGui : : Checkbox ( " Force Windows CE " , & settings . dreamcast . ForceWindowsCE ) ;
ImGui : : SameLine ( ) ;
2020-04-09 09:44:19 +00:00
ShowHelpMarker ( " Enable full MMU emulation and other Windows CE settings. Do not enable unless necessary " ) ;
2019-08-31 20:10:09 +00:00
# ifndef __ANDROID
2019-02-09 20:20:03 +00:00
ImGui : : Checkbox ( " Serial Console " , & settings . debug . SerialConsole ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Dump the Dreamcast serial console to stdout " ) ;
2019-02-09 20:20:03 +00:00
# endif
ImGui : : Checkbox ( " Dump Textures " , & settings . rend . DumpTextures ) ;
2019-02-09 21:15:08 +00:00
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Dump all textures into data/texdump/<game id> " ) ;
2020-04-02 10:20:03 +00:00
bool logToFile = cfgLoadBool ( " log " , " LogToFile " , false ) ;
bool newLogToFile = logToFile ;
ImGui : : Checkbox ( " Log to File " , & newLogToFile ) ;
if ( logToFile ! = newLogToFile )
{
cfgSaveBool ( " log " , " LogToFile " , newLogToFile ) ;
LogManager : : Shutdown ( ) ;
LogManager : : Init ( ) ;
}
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " Log debug information to flycast.log " ) ;
2019-02-09 20:20:03 +00:00
}
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : EndTabItem ( ) ;
}
2019-03-04 23:54:01 +00:00
if ( ImGui : : BeginTabItem ( " About " ) )
{
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
2019-06-20 19:50:19 +00:00
if ( ImGui : : CollapsingHeader ( " Flycast " , ImGuiTreeNodeFlags_DefaultOpen ) )
2019-03-04 23:54:01 +00:00
{
2019-03-30 11:32:37 +00:00
ImGui : : Text ( " Version: %s " , REICAST_VERSION ) ;
ImGui : : Text ( " Git Hash: %s " , GIT_HASH ) ;
ImGui : : Text ( " Build Date: %s " , BUILD_DATE ) ;
2019-03-04 23:54:01 +00:00
ImGui : : Text ( " Target: %s " ,
2019-07-09 21:52:19 +00:00
settings . platform . system = = DC_PLATFORM_DREAMCAST ?
2019-03-04 23:54:01 +00:00
" Dreamcast "
2019-07-09 21:52:19 +00:00
: settings . platform . system = = DC_PLATFORM_NAOMI ?
2019-03-04 23:54:01 +00:00
" Naomi "
2019-07-09 21:52:19 +00:00
: settings . platform . system = = DC_PLATFORM_ATOMISWAVE ?
2019-03-04 23:54:01 +00:00
" Atomiswave "
2019-07-09 21:52:19 +00:00
:
2019-03-04 23:54:01 +00:00
" Unknown "
) ;
}
if ( ImGui : : CollapsingHeader ( " Platform " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : Text ( " CPU: %s " ,
# if HOST_CPU == CPU_X86
" x86 "
# elif HOST_CPU == CPU_ARM
" ARM "
# elif HOST_CPU == CPU_MIPS
" MIPS "
# elif HOST_CPU == CPU_X64
" x86/64 "
# elif HOST_CPU == CPU_GENERIC
" Generic "
# elif HOST_CPU == CPU_ARM64
" ARM64 "
# else
" Unknown "
# endif
) ;
ImGui : : Text ( " Operating System: %s " ,
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2019-03-04 23:54:01 +00:00
" Android "
# elif HOST_OS == OS_LINUX
" Linux "
# elif HOST_OS == OS_DARWIN
2019-07-24 16:24:58 +00:00
# ifdef TARGET_IPHONE
2019-03-04 23:54:01 +00:00
" iOS "
# else
" OSX "
# endif
2019-08-25 17:29:56 +00:00
# elif defined(_WIN32)
2019-03-04 23:54:01 +00:00
" Windows "
# else
" Unknown "
# endif
) ;
}
2019-10-15 14:52:02 +00:00
if ( settings . pvr . IsOpenGL ( ) )
{
if ( ImGui : : CollapsingHeader ( " Open GL " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : Text ( " Renderer: %s " , ( const char * ) glGetString ( GL_RENDERER ) ) ;
ImGui : : Text ( " Version: %s " , ( const char * ) glGetString ( GL_VERSION ) ) ;
}
}
# ifdef USE_VULKAN
2019-11-13 19:08:14 +00:00
else if ( settings . pvr . rend = = 4 | | settings . pvr . rend = = 5 )
2019-10-15 14:52:02 +00:00
{
if ( ImGui : : CollapsingHeader ( " Vulkan " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
std : : string name = VulkanContext : : Instance ( ) - > GetDriverName ( ) ;
ImGui : : Text ( " Driver Name: %s " , name . c_str ( ) ) ;
std : : string version = VulkanContext : : Instance ( ) - > GetDriverVersion ( ) ;
ImGui : : Text ( " Version: %s " , version . c_str ( ) ) ;
}
}
# endif
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2019-03-04 23:54:01 +00:00
ImGui : : Separator ( ) ;
if ( ImGui : : Button ( " Send Logs " ) ) {
void android_send_logs ( ) ;
android_send_logs ( ) ;
}
# endif
ImGui : : PopStyleVar ( ) ;
ImGui : : EndTabItem ( ) ;
}
2019-02-06 18:57:13 +00:00
ImGui : : EndTabBar ( ) ;
}
2019-02-09 20:20:03 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : End ( ) ;
2019-02-20 22:22:58 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : Render ( ) ;
2019-10-05 09:50:14 +00:00
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) , false ) ;
2019-02-06 18:57:13 +00:00
2019-11-13 19:08:14 +00:00
if ( vulkan ^ ( settings . pvr . rend = = 4 | | settings . pvr . rend = = 5 ) )
2020-03-12 15:09:05 +00:00
pvr_rend = ! vulkan ? 0 : settings . pvr . rend = = 3 ? 5 : 4 ;
renderer_changed = pvr_rend ;
2019-02-06 18:57:13 +00:00
settings . dynarec . Enable = ( bool ) dynarec_enabled ;
}
2020-04-22 17:11:49 +00:00
void gui_display_notification ( const char * msg , int duration )
{
std : : lock_guard < std : : mutex > lock ( osd_message_mutex ) ;
osd_message = msg ;
osd_message_end = os_GetSeconds ( ) + ( double ) duration / 1000.0 ;
}
static std : : string get_notification ( )
{
std : : lock_guard < std : : mutex > lock ( osd_message_mutex ) ;
if ( ! osd_message . empty ( ) & & os_GetSeconds ( ) > = osd_message_end )
osd_message . clear ( ) ;
return osd_message ;
}
2019-02-25 16:52:53 +00:00
static void gui_display_demo ( )
{
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
ImGui : : ShowDemoWindow ( ) ;
ImGui : : Render ( ) ;
2019-10-05 09:50:14 +00:00
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) , false ) ;
2019-02-25 16:52:53 +00:00
}
static void gui_display_content ( )
{
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( screen_width , screen_height ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0 ) ;
ImGui : : Begin ( " ##main " , NULL , ImGuiWindowFlags_NoDecoration ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 20 * scaling , 8 * scaling ) ) ; // from 8, 4
ImGui : : AlignTextToFramePadding ( ) ;
ImGui : : Text ( " GAMES " ) ;
static ImGuiTextFilter filter ;
if ( KeyboardDevice : : GetInstance ( ) ! = NULL )
{
ImGui : : SameLine ( 0 , 32 * scaling ) ;
filter . Draw ( " Filter " ) ;
}
2020-01-30 17:59:26 +00:00
if ( gui_state ! = SelectDisk )
{
ImGui : : SameLine ( ImGui : : GetContentRegionAvailWidth ( ) - ImGui : : CalcTextSize ( " Settings " ) . x - ImGui : : GetStyle ( ) . FramePadding . x * 2.0f /*+ ImGui::GetStyle().ItemSpacing.x*/ ) ;
if ( ImGui : : Button ( " Settings " ) ) //, ImVec2(0, 30 * scaling)))
gui_state = Settings ;
}
2019-02-25 16:52:53 +00:00
ImGui : : PopStyleVar ( ) ;
2020-04-09 09:44:19 +00:00
scanner . fetch_game_list ( ) ;
2019-02-25 16:52:53 +00:00
// Only if Filter and Settings aren't focused... ImGui::SetNextWindowFocus();
ImGui : : BeginChild ( ImGui : : GetID ( " library " ) , ImVec2 ( 0 , 0 ) , true ) ;
{
ImGui : : PushStyleVar ( ImGuiStyleVar_ItemSpacing , ImVec2 ( 8 * scaling , 20 * scaling ) ) ; // from 8, 4
2019-03-26 16:20:44 +00:00
ImGui : : PushID ( " bios " ) ;
if ( ImGui : : Selectable ( " Dreamcast BIOS " ) )
{
2020-04-20 16:52:02 +00:00
gui_state = Closed ;
2019-03-26 16:20:44 +00:00
gui_start_game ( " " ) ;
}
ImGui : : PopID ( ) ;
2020-04-09 09:44:19 +00:00
{
scanner . get_mutex ( ) . lock ( ) ;
for ( const auto & game : scanner . get_game_list ( ) )
{
if ( gui_state = = SelectDisk )
2019-02-25 16:52:53 +00:00
{
2020-04-09 09:44:19 +00:00
std : : string extension = get_file_extension ( game . path ) ;
if ( extension ! = " gdi " & & extension ! = " chd "
& & extension ! = " cdi " & & extension ! = " cue " )
// Only dreamcast disks
continue ;
}
if ( filter . PassFilter ( game . name . c_str ( ) ) )
{
ImGui : : PushID ( game . path . c_str ( ) ) ;
if ( ImGui : : Selectable ( game . name . c_str ( ) ) )
2020-01-30 17:59:26 +00:00
{
2020-04-09 09:44:19 +00:00
if ( gui_state = = SelectDisk )
{
strcpy ( settings . imgread . ImagePath , game . path . c_str ( ) ) ;
DiscSwap ( ) ;
gui_state = Closed ;
}
else
{
scanner . get_mutex ( ) . unlock ( ) ;
2020-04-20 16:52:02 +00:00
gui_state = Closed ;
2020-04-09 09:44:19 +00:00
gui_start_game ( game . path ) ;
scanner . get_mutex ( ) . lock ( ) ;
}
2020-01-30 17:59:26 +00:00
}
2020-04-09 09:44:19 +00:00
ImGui : : PopID ( ) ;
2019-02-25 16:52:53 +00:00
}
2020-04-09 09:44:19 +00:00
}
scanner . get_mutex ( ) . unlock ( ) ;
}
2019-02-25 16:52:53 +00:00
ImGui : : PopStyleVar ( ) ;
}
ImGui : : EndChild ( ) ;
ImGui : : End ( ) ;
ImGui : : PopStyleVar ( ) ;
2019-03-04 23:54:01 +00:00
error_popup ( ) ;
2019-02-25 16:52:53 +00:00
ImGui : : Render ( ) ;
2019-10-05 09:50:14 +00:00
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) , false ) ;
2019-02-25 16:52:53 +00:00
}
2020-04-22 17:11:49 +00:00
static void systemdir_selected_callback ( bool cancelled , std : : string selection )
2019-02-25 16:52:53 +00:00
{
if ( ! cancelled )
{
set_user_config_dir ( selection ) ;
set_user_data_dir ( selection ) ;
if ( cfgOpen ( ) )
{
LoadSettings ( false ) ;
2019-11-13 19:08:14 +00:00
// Make sure the renderer type doesn't change mid-flight
settings . pvr . rend = 0 ;
2019-02-25 16:52:53 +00:00
gui_state = Main ;
2019-03-04 23:54:01 +00:00
if ( settings . dreamcast . ContentPath . empty ( ) )
settings . dreamcast . ContentPath . push_back ( selection ) ;
SaveSettings ( ) ;
2019-02-25 16:52:53 +00:00
}
}
}
2020-04-22 17:11:49 +00:00
static void gui_display_onboarding ( )
2019-02-25 16:52:53 +00:00
{
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
ImGui : : OpenPopup ( " Select System Directory " ) ;
select_directory_popup ( " Select System Directory " , scaling , & systemdir_selected_callback ) ;
ImGui : : Render ( ) ;
2019-10-05 09:50:14 +00:00
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) , false ) ;
2019-02-25 16:52:53 +00:00
}
2020-04-22 17:11:49 +00:00
static std : : future < bool > networkStatus ;
static void start_network ( )
{
networkStatus = naomiNetwork . startNetworkAsync ( ) ;
gui_state = NetworkStart ;
}
static void gui_network_start ( )
{
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
ImGui : : SetNextWindowPos ( ImVec2 ( screen_width / 2 , screen_height / 2 ) , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( 330 * scaling , 180 * scaling ) ) ;
ImGui : : Begin ( " ##network " , NULL , ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 20 * scaling , 10 * scaling ) ) ;
ImGui : : AlignTextToFramePadding ( ) ;
ImGui : : SetCursorPosX ( 20.f * scaling ) ;
if ( networkStatus . wait_for ( std : : chrono : : milliseconds ( 0 ) ) = = std : : future_status : : ready )
{
if ( networkStatus . get ( ) )
{
gui_state = Closed ;
ImGui : : Text ( " STARTING... " ) ;
}
else
{
gui_state = Main ;
settings . imgread . ImagePath [ 0 ] = ' \0 ' ;
}
}
else
{
ImGui : : Text ( " STARTING NETWORK... " ) ;
if ( settings . network . ActAsServer )
ImGui : : Text ( " Press Start to start the game now. " ) ;
}
ImGui : : Text ( " %s " , get_notification ( ) . c_str ( ) ) ;
float currentwidth = ImGui : : GetContentRegionAvailWidth ( ) ;
ImGui : : SetCursorPosX ( ( currentwidth - 100.f * scaling ) / 2.f + ImGui : : GetStyle ( ) . WindowPadding . x ) ;
ImGui : : SetCursorPosY ( 126.f * scaling ) ;
if ( ImGui : : Button ( " Cancel " , ImVec2 ( 100.f * scaling , 0.f ) ) )
{
naomiNetwork . terminate ( ) ;
networkStatus . get ( ) ;
gui_state = Main ;
settings . imgread . ImagePath [ 0 ] = ' \0 ' ;
}
ImGui : : PopStyleVar ( ) ;
ImGui : : End ( ) ;
ImGui : : Render ( ) ;
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) , false ) ;
if ( ( kcode [ 0 ] & DC_BTN_START ) = = 0 )
naomiNetwork . startNow ( ) ;
}
static void gui_display_loadscreen ( )
2020-04-20 16:52:02 +00:00
{
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
ImGui : : SetNextWindowPos ( ImVec2 ( screen_width / 2 , screen_height / 2 ) , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( 330 * scaling , 180 * scaling ) ) ;
ImGui : : Begin ( " ##loading " , NULL , ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 20 * scaling , 10 * scaling ) ) ;
ImGui : : AlignTextToFramePadding ( ) ;
ImGui : : SetCursorPosX ( 20.f * scaling ) ;
if ( dc_is_load_done ( ) )
{
try {
dc_get_load_status ( ) ;
2020-04-22 17:11:49 +00:00
if ( NaomiNetworkSupported ( ) )
{
start_network ( ) ;
}
else
{
gui_state = Closed ;
ImGui : : Text ( " STARTING... " ) ;
}
} catch ( const ReicastException & ex ) {
2020-04-20 16:52:02 +00:00
ERROR_LOG ( BOOT , " %s " , ex . reason . c_str ( ) ) ;
error_msg = ex . reason ;
# ifdef TEST_AUTOMATION
die ( " Game load failed " ) ;
# endif
gui_state = Main ;
settings . imgread . ImagePath [ 0 ] = ' \0 ' ;
}
}
else
{
ImGui : : Text ( " LOADING... " ) ;
2020-04-22 17:11:49 +00:00
ImGui : : SameLine ( ) ;
ImGui : : Text ( " %s " , get_notification ( ) . c_str ( ) ) ;
2020-04-20 16:52:02 +00:00
float currentwidth = ImGui : : GetContentRegionAvailWidth ( ) ;
ImGui : : SetCursorPosX ( ( currentwidth - 100.f * scaling ) / 2.f + ImGui : : GetStyle ( ) . WindowPadding . x ) ;
ImGui : : SetCursorPosY ( 126.f * scaling ) ;
if ( ImGui : : Button ( " Cancel " , ImVec2 ( 100.f * scaling , 0.f ) ) )
{
dc_cancel_load ( ) ;
gui_state = Main ;
}
}
ImGui : : PopStyleVar ( ) ;
ImGui : : End ( ) ;
ImGui : : Render ( ) ;
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) , false ) ;
}
2019-02-06 18:57:13 +00:00
void gui_display_ui ( )
{
switch ( gui_state )
{
case Settings :
gui_display_settings ( ) ;
break ;
case Commands :
gui_display_commands ( ) ;
break ;
2019-02-25 16:52:53 +00:00
case Main :
//gui_display_demo();
2019-03-13 20:54:04 +00:00
{
2020-01-30 17:59:26 +00:00
std : : string game_file = settings . imgread . ImagePath ;
2019-03-13 20:54:04 +00:00
if ( ! game_file . empty ( ) )
gui_start_game ( game_file ) ;
else
gui_display_content ( ) ;
}
2019-02-25 16:52:53 +00:00
break ;
2019-02-06 18:57:13 +00:00
case Closed :
break ;
2019-02-25 16:52:53 +00:00
case Onboarding :
gui_display_onboarding ( ) ;
break ;
2019-03-04 23:54:01 +00:00
case VJoyEdit :
break ;
case VJoyEditCommands :
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2019-03-04 23:54:01 +00:00
gui_display_vjoy_commands ( screen_width , screen_height , scaling ) ;
# endif
break ;
2020-01-30 17:59:26 +00:00
case SelectDisk :
gui_display_content ( ) ;
break ;
2020-04-20 16:52:02 +00:00
case Loading :
gui_display_loadscreen ( ) ;
break ;
2020-04-22 17:11:49 +00:00
case NetworkStart :
gui_network_start ( ) ;
break ;
default :
die ( " Unknown UI state " ) ;
break ;
2019-02-06 18:57:13 +00:00
}
if ( gui_state = = Closed )
2019-02-25 16:52:53 +00:00
dc_resume ( ) ;
2019-02-06 18:57:13 +00:00
}
2019-02-17 23:25:06 +00:00
2019-02-27 22:02:25 +00:00
static float LastFPSTime ;
static int lastFrameCount = 0 ;
static float fps = - 1 ;
2019-09-27 12:15:29 +00:00
extern bool fast_forward_mode ;
2019-02-27 22:02:25 +00:00
static std : : string getFPSNotification ( )
{
if ( settings . rend . ShowFPS )
{
double now = os_GetSeconds ( ) ;
if ( now - LastFPSTime > = 1.0 ) {
fps = ( FrameCount - lastFrameCount ) / ( now - LastFPSTime ) ;
LastFPSTime = now ;
lastFrameCount = FrameCount ;
}
2019-03-04 23:54:01 +00:00
if ( fps > = 0.f & & fps < 9999.f ) {
2019-02-27 22:02:25 +00:00
char text [ 32 ] ;
2019-09-27 12:15:29 +00:00
snprintf ( text , sizeof ( text ) , " F:%.1f%s " , fps , fast_forward_mode ? " >> " : " " ) ;
2019-02-27 22:02:25 +00:00
return std : : string ( text ) ;
}
}
2019-09-27 12:15:29 +00:00
return std : : string ( fast_forward_mode ? " >> " : " " ) ;
2019-02-27 22:02:25 +00:00
}
void gui_display_osd ( )
{
2019-03-04 23:54:01 +00:00
if ( gui_state = = VJoyEdit )
return ;
2020-04-22 17:11:49 +00:00
std : : string message = get_notification ( ) ;
if ( message . empty ( ) )
2019-02-27 22:02:25 +00:00
message = getFPSNotification ( ) ;
2019-04-08 13:54:37 +00:00
if ( ! message . empty ( ) | | settings . rend . FloatVMUs )
{
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
2019-02-27 22:02:25 +00:00
2019-04-08 13:54:37 +00:00
if ( ! message . empty ( ) )
{
ImGui : : SetNextWindowBgAlpha ( 0 ) ;
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , screen_height ) , ImGuiCond_Always , ImVec2 ( 0.f , 1.f ) ) ; // Lower left corner
2019-09-24 21:59:36 +00:00
ImGui : : SetNextWindowSize ( ImVec2 ( screen_width , 0 ) ) ;
2019-04-08 13:54:37 +00:00
ImGui : : Begin ( " ##osd " , NULL , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground ) ;
ImGui : : SetWindowFontScale ( 1.5 ) ;
ImGui : : TextColored ( ImVec4 ( 1 , 1 , 0 , 0.7 ) , " %s " , message . c_str ( ) ) ;
ImGui : : End ( ) ;
}
if ( settings . rend . FloatVMUs )
display_vmus ( ) ;
2019-12-25 12:09:54 +00:00
// gui_plot_render_time(screen_width, screen_height);
2019-02-27 22:02:25 +00:00
2019-04-08 13:54:37 +00:00
ImGui : : Render ( ) ;
2019-10-05 09:50:14 +00:00
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) ) ;
2019-04-08 13:54:37 +00:00
}
2019-02-27 22:02:25 +00:00
}
2019-02-25 16:52:53 +00:00
void gui_open_onboarding ( )
{
gui_state = Onboarding ;
}
2019-02-17 23:25:06 +00:00
void gui_term ( )
{
2019-10-19 16:34:24 +00:00
if ( inited )
{
inited = false ;
term_vmus ( ) ;
if ( settings . pvr . IsOpenGL ( ) )
ImGui_ImplOpenGL3_Shutdown ( ) ;
ImGui : : DestroyContext ( ) ;
}
2019-02-17 23:25:06 +00:00
}
2019-03-04 23:54:01 +00:00
2020-01-31 22:51:12 +00:00
int msgboxf ( const char * text , unsigned int type , . . . ) {
2019-03-04 23:54:01 +00:00
va_list args ;
2020-01-31 22:51:12 +00:00
char temp [ 2048 ] ;
2019-03-04 23:54:01 +00:00
va_start ( args , type ) ;
vsnprintf ( temp , sizeof ( temp ) , text , args ) ;
va_end ( args ) ;
2019-07-01 15:17:08 +00:00
ERROR_LOG ( COMMON , " %s " , temp ) ;
2019-03-04 23:54:01 +00:00
gui_display_notification ( temp , 2000 ) ;
return 1 ;
}
2019-03-27 20:09:53 +00:00
extern bool subfolders_read ;
void gui_refresh_files ( )
{
2020-04-09 09:44:19 +00:00
scanner . refresh ( ) ;
2019-03-27 20:09:53 +00:00
subfolders_read = false ;
}
2019-03-29 16:35:00 +00:00
# define VMU_WIDTH (70 * 48 * scaling / 32)
# define VMU_HEIGHT (70 * scaling)
# define VMU_PADDING (8 * scaling)
2019-12-25 12:09:54 +00:00
u32 vmu_lcd_data [ 8 ] [ 48 * 32 ] ;
bool vmu_lcd_status [ 8 ] ;
bool vmu_lcd_changed [ 8 ] ;
2019-03-29 16:35:00 +00:00
static ImTextureID vmu_lcd_tex_ids [ 8 ] ;
2019-03-29 18:54:59 +00:00
void push_vmu_screen ( int bus_id , int bus_port , u8 * buffer )
2019-03-29 16:35:00 +00:00
{
2019-03-29 18:54:59 +00:00
int vmu_id = bus_id * 2 + bus_port ;
2020-03-12 15:09:05 +00:00
if ( vmu_id < 0 | | vmu_id > = ( int ) ARRAY_SIZE ( vmu_lcd_data ) )
2019-03-29 18:54:59 +00:00
return ;
2019-03-29 16:35:00 +00:00
u32 * p = & vmu_lcd_data [ vmu_id ] [ 0 ] ;
2020-03-12 15:09:05 +00:00
for ( int i = 0 ; i < ( int ) ARRAY_SIZE ( vmu_lcd_data [ vmu_id ] ) ; i + + , buffer + + )
2019-03-29 16:35:00 +00:00
* p + + = * buffer ! = 0 ? 0xFFFFFFFFu : 0xFF000000u ;
vmu_lcd_status [ vmu_id ] = true ;
2019-12-25 12:09:54 +00:00
vmu_lcd_changed [ vmu_id ] = true ;
2019-03-29 16:35:00 +00:00
}
static const int vmu_coords [ 8 ] [ 2 ] = {
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 1 , 0 } ,
{ 1 , 0 } ,
{ 0 , 1 } ,
{ 0 , 1 } ,
{ 1 , 1 } ,
{ 1 , 1 } ,
} ;
static void display_vmus ( )
{
if ( ! game_started )
return ;
2019-10-05 09:50:14 +00:00
if ( ! settings . pvr . IsOpenGL ( ) )
return ;
2019-03-29 16:35:00 +00:00
ImGui : : SetNextWindowBgAlpha ( 0 ) ;
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( screen_width , screen_height ) ) ;
ImGui : : Begin ( " vmu-window " , NULL , ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs
| ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoFocusOnAppearing ) ;
for ( int i = 0 ; i < 8 ; i + + )
{
if ( ! vmu_lcd_status [ i ] )
continue ;
if ( vmu_lcd_tex_ids [ i ] ! = ( ImTextureID ) 0 )
ImGui_ImplOpenGL3_DeleteVmuTexture ( vmu_lcd_tex_ids [ i ] ) ;
vmu_lcd_tex_ids [ i ] = ImGui_ImplOpenGL3_CreateVmuTexture ( vmu_lcd_data [ i ] ) ;
int x = vmu_coords [ i ] [ 0 ] ;
int y = vmu_coords [ i ] [ 1 ] ;
ImVec2 pos ;
if ( x = = 0 )
pos . x = VMU_PADDING ;
else
pos . x = screen_width - VMU_WIDTH - VMU_PADDING ;
if ( y = = 0 )
{
pos . y = VMU_PADDING ;
if ( i & 1 )
pos . y + = VMU_HEIGHT + VMU_PADDING ;
}
else
{
pos . y = screen_height - VMU_HEIGHT - VMU_PADDING ;
if ( i & 1 )
pos . y - = VMU_HEIGHT + VMU_PADDING ;
}
ImVec2 pos_b ( pos . x + VMU_WIDTH , pos . y + VMU_HEIGHT ) ;
ImGui : : GetWindowDrawList ( ) - > AddImage ( vmu_lcd_tex_ids [ i ] , pos , pos_b , ImVec2 ( 0 , 1 ) , ImVec2 ( 1 , 0 ) , 0xC0ffffff ) ;
}
ImGui : : End ( ) ;
}
static void reset_vmus ( )
{
2020-03-12 15:09:05 +00:00
for ( u32 i = 0 ; i < ARRAY_SIZE ( vmu_lcd_status ) ; i + + )
2019-03-29 16:35:00 +00:00
vmu_lcd_status [ i ] = false ;
}
static void term_vmus ( )
{
2019-10-05 09:50:14 +00:00
if ( ! settings . pvr . IsOpenGL ( ) )
return ;
2020-03-12 15:09:05 +00:00
for ( u32 i = 0 ; i < ARRAY_SIZE ( vmu_lcd_status ) ; i + + )
2019-03-29 16:35:00 +00:00
{
if ( vmu_lcd_tex_ids [ i ] ! = ( ImTextureID ) 0 )
{
ImGui_ImplOpenGL3_DeleteVmuTexture ( vmu_lcd_tex_ids [ i ] ) ;
vmu_lcd_tex_ids [ i ] = ( ImTextureID ) 0 ;
}
}
}