2019-02-06 21:28:04 +00:00
/*
Copyright 2019 flyinghead
2021-03-16 09:15:23 +00:00
This file is part of Flycast .
2019-02-06 21:28:04 +00:00
2021-03-16 09:15:23 +00:00
Flycast is free software : you can redistribute it and / or modify
2019-02-06 21:28:04 +00:00
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 .
2021-03-16 09:15:23 +00:00
Flycast is distributed in the hope that it will be useful ,
2019-02-06 21:28:04 +00:00
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
2021-03-16 09:15:23 +00:00
along with Flycast . If not , see < https : //www.gnu.org/licenses/>.
2019-02-06 21:28:04 +00:00
*/
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"
2020-12-15 14:09:42 +00:00
# include "osd.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"
2020-12-15 14:09:42 +00:00
# include "wsi/context.h"
2019-02-12 10:30:24 +00:00
# include "input/gamepad_device.h"
2019-02-25 16:52:53 +00:00
# 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"
2020-12-15 14:09:42 +00:00
# include "oslib/oslib.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"
2020-12-15 14:09:42 +00:00
# include "rend/mainui.h"
2019-02-06 18:57:13 +00:00
2020-12-02 13:40:50 +00:00
extern void UpdateInputState ( ) ;
2021-01-19 22:52:28 +00:00
static bool game_started ;
2019-02-06 18:57:13 +00:00
2021-04-29 16:58:04 +00:00
extern u8 kb_shift [ MAPLE_PORTS ] ; // shift keys pressed (bitmask)
extern u8 kb_key [ MAPLE_PORTS ] [ 6 ] ; // normal keys pressed
2019-02-06 18:57:13 +00:00
int screen_dpi = 96 ;
2021-05-02 09:31:44 +00:00
int insetLeft , insetRight , insetTop , insetBottom ;
2019-02-06 18:57:13 +00:00
static bool inited = false ;
2021-02-17 22:03:14 +00:00
float scaling = 1 ;
2021-03-01 09:13:40 +00:00
GuiState gui_state = GuiState : : Main ;
2021-04-20 13:57:30 +00:00
static bool commandLineStart ;
2021-04-29 16:58:04 +00:00
static u32 mouseButtons ;
static int mouseX , mouseY ;
static float mouseWheel ;
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
2021-06-27 10:49:47 +00:00
static int map_system = 0 ;
2019-03-29 16:35:00 +00:00
static void display_vmus ( ) ;
static void reset_vmus ( ) ;
static void term_vmus ( ) ;
2021-01-23 14:59:57 +00:00
static void displayCrosshairs ( ) ;
2019-03-29 16:35:00 +00:00
2020-04-09 09:44:19 +00:00
GameScanner scanner ;
2021-01-19 22:52:28 +00:00
static void emuEventCallback ( Event event )
{
2021-03-01 09:13:40 +00:00
switch ( event )
{
case Event : : Resume :
2021-01-19 22:52:28 +00:00
game_started = true ;
2021-03-01 09:13:40 +00:00
break ;
case Event : : Start :
2021-07-05 17:44:08 +00:00
GamepadDevice : : load_system_mappings ( ) ;
if ( settings . platform . system = = DC_PLATFORM_NAOMI )
SetNaomiNetworkConfig ( - 1 ) ;
2021-06-04 09:11:23 +00:00
if ( config : : AutoLoadState & & settings . imgread . ImagePath [ 0 ] ! = ' \0 ' )
2021-06-03 11:50:40 +00:00
dc_loadstate ( config : : SavestateSlot ) ;
2021-03-01 09:13:40 +00:00
break ;
case Event : : Terminate :
2021-06-04 09:11:23 +00:00
if ( config : : AutoSaveState & & settings . imgread . ImagePath [ 0 ] ! = ' \0 ' )
2021-06-03 11:50:40 +00:00
dc_savestate ( config : : SavestateSlot ) ;
2021-03-01 09:13:40 +00:00
break ;
default :
break ;
}
2021-01-19 22:52:28 +00:00
}
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;
2021-08-06 08:30:30 +00:00
# if defined(__ANDROID__) || defined(TARGET_IPHONE)
2019-02-09 20:20:03 +00:00
ImGui : : GetStyle ( ) . TouchExtraPadding = ImVec2 ( 1 , 1 ) ; // from 0,0
# endif
2019-02-06 18:57:13 +00:00
// Setup Platform/Renderer bindings
2021-03-01 09:13:40 +00:00
if ( config : : RendererType . isOpenGL ( ) )
2019-10-05 09:50:14 +00:00
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);
2021-08-06 08:30:30 +00:00
# if !(defined(_WIN32) || defined(__APPLE__) || defined(__SWITCH__)) || defined(TARGET_IPHONE)
2021-02-17 23:24:05 +00:00
scaling = std : : max ( 1.f , screen_dpi / 100.f * 0.75f ) ;
# endif
2019-02-06 18:57:13 +00:00
if ( scaling > 1 )
ImGui : : GetStyle ( ) . ScaleAllSizes ( scaling ) ;
2021-01-19 10:11:01 +00:00
static const ImWchar ranges [ ] =
{
0x0020 , 0xFFFF , // All chars
0 ,
} ;
io . Fonts - > AddFontFromMemoryCompressedTTF ( roboto_medium_compressed_data , roboto_medium_compressed_size , 17.f * scaling , nullptr , ranges ) ;
2021-01-31 15:08:10 +00:00
ImFontConfig font_cfg ;
font_cfg . MergeMode = true ;
# ifdef _WIN32
u32 cp = GetACP ( ) ;
std : : string fontDir = std : : string ( nowide : : getenv ( " SYSTEMROOT " ) ) + " \\ Fonts \\ " ;
switch ( cp )
{
case 932 : // Japanese
{
font_cfg . FontNo = 2 ; // UIGothic
ImFont * font = io . Fonts - > AddFontFromFileTTF ( ( fontDir + " msgothic.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , io . Fonts - > GetGlyphRangesJapanese ( ) ) ;
font_cfg . FontNo = 2 ; // Meiryo UI
if ( font = = nullptr )
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " Meiryo.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , io . Fonts - > GetGlyphRangesJapanese ( ) ) ;
}
break ;
case 949 : // Korean
{
ImFont * font = io . Fonts - > AddFontFromFileTTF ( ( fontDir + " Malgun.ttf " ) . c_str ( ) , 17.f * scaling , & font_cfg , io . Fonts - > GetGlyphRangesKorean ( ) ) ;
if ( font = = nullptr )
{
font_cfg . FontNo = 2 ; // Dotum
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " Gulim.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , io . Fonts - > GetGlyphRangesKorean ( ) ) ;
}
}
break ;
case 950 : // Traditional Chinese
{
font_cfg . FontNo = 1 ; // Microsoft JhengHei UI Regular
2021-02-01 11:38:29 +00:00
ImFont * font = io . Fonts - > AddFontFromFileTTF ( ( fontDir + " Msjh.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , GetGlyphRangesChineseTraditionalOfficial ( ) ) ;
2021-01-31 15:08:10 +00:00
font_cfg . FontNo = 0 ;
if ( font = = nullptr )
2021-02-01 11:38:29 +00:00
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " MSJH.ttf " ) . c_str ( ) , 17.f * scaling , & font_cfg , GetGlyphRangesChineseTraditionalOfficial ( ) ) ;
2021-01-31 15:08:10 +00:00
}
break ;
case 936 : // Simplified Chinese
2021-02-01 11:38:29 +00:00
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " Simsun.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , GetGlyphRangesChineseSimplifiedOfficial ( ) ) ;
2021-01-31 15:08:10 +00:00
break ;
default :
break ;
}
2021-08-06 08:30:30 +00:00
# elif defined(__APPLE__) && !defined(TARGET_IPHONE)
2021-02-01 11:40:12 +00:00
std : : string fontDir = std : : string ( " /System/Library/Fonts/ " ) ;
extern std : : string os_Locale ( ) ;
std : : string locale = os_Locale ( ) ;
if ( locale . find ( " ja " ) = = 0 ) // Japanese
{
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " ヒラギノ角ゴシック W4.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , io . Fonts - > GetGlyphRangesJapanese ( ) ) ;
}
else if ( locale . find ( " ko " ) = = 0 ) // Korean
{
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " AppleSDGothicNeo.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , io . Fonts - > GetGlyphRangesKorean ( ) ) ;
}
2021-02-01 11:57:28 +00:00
else if ( locale . find ( " zh-Hant " ) = = 0 ) // Traditional Chinese
2021-02-01 11:40:12 +00:00
{
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " PingFang.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , GetGlyphRangesChineseTraditionalOfficial ( ) ) ;
}
2021-02-01 11:57:28 +00:00
else if ( locale . find ( " zh-Hans " ) = = 0 ) // Simplified Chinese
2021-02-01 11:40:12 +00:00
{
io . Fonts - > AddFontFromFileTTF ( ( fontDir + " PingFang.ttc " ) . c_str ( ) , 17.f * scaling , & font_cfg , GetGlyphRangesChineseSimplifiedOfficial ( ) ) ;
}
2021-04-22 09:12:51 +00:00
# elif defined(__ANDROID__)
if ( getenv ( " FLYCAST_LOCALE " ) ! = nullptr )
{
const ImWchar * glyphRanges = nullptr ;
std : : string locale = getenv ( " FLYCAST_LOCALE " ) ;
if ( locale . find ( " ja " ) = = 0 ) // Japanese
glyphRanges = io . Fonts - > GetGlyphRangesJapanese ( ) ;
else if ( locale . find ( " ko " ) = = 0 ) // Korean
glyphRanges = io . Fonts - > GetGlyphRangesKorean ( ) ;
2021-04-30 16:26:35 +00:00
else if ( locale . find ( " zh_TW " ) = = 0
| | locale . find ( " zh_HK " ) = = 0 ) // Traditional Chinese
2021-04-22 09:12:51 +00:00
glyphRanges = GetGlyphRangesChineseTraditionalOfficial ( ) ;
else if ( locale . find ( " zh_CN " ) = = 0 ) // Simplified Chinese
glyphRanges = GetGlyphRangesChineseSimplifiedOfficial ( ) ;
if ( glyphRanges ! = nullptr )
io . Fonts - > AddFontFromFileTTF ( " /system/fonts/NotoSansCJK-Regular.ttc " , 17.f * scaling , & font_cfg , glyphRanges ) ;
}
2021-08-06 08:30:30 +00:00
// TODO Linux, iOS, ...
2021-01-31 15:08:10 +00:00
# endif
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 ) ;
2021-01-19 22:52:28 +00:00
EventManager : : listen ( Event : : Resume , emuEventCallback ) ;
2021-03-01 09:13:40 +00:00
EventManager : : listen ( Event : : Start , emuEventCallback ) ;
EventManager : : listen ( Event : : Terminate , emuEventCallback ) ;
2019-02-06 18:57:13 +00:00
}
2021-04-29 16:58:04 +00:00
void gui_keyboard_input ( u16 wc )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
if ( io . WantCaptureKeyboard )
io . AddInputCharacter ( wc ) ;
}
void gui_keyboard_inputUTF8 ( const std : : string & s )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
if ( io . WantCaptureKeyboard )
io . AddInputCharactersUTF8 ( s . c_str ( ) ) ;
}
void gui_set_mouse_position ( int x , int y )
{
mouseX = x ;
mouseY = y ;
}
void gui_set_mouse_button ( int button , bool pressed )
{
if ( pressed )
mouseButtons | = 1 < < button ;
else
mouseButtons & = ~ ( 1 < < button ) ;
}
void gui_set_mouse_wheel ( float delta )
{
mouseWheel + = delta ;
}
2021-04-06 09:41:04 +00:00
static void ImGui_Impl_NewFrame ( )
2019-02-06 18:57:13 +00:00
{
2021-03-01 09:13:40 +00:00
if ( config : : RendererType . isOpenGL ( ) )
2019-10-05 09:50:14 +00:00
ImGui_ImplOpenGL3_NewFrame ( ) ;
2021-04-12 20:49:04 +00:00
# ifdef _WIN32
else if ( config : : RendererType . isDirectX ( ) )
ImGui_ImplDX9_NewFrame ( ) ;
# endif
2021-06-07 10:18:05 +00:00
ImGui : : GetIO ( ) . DisplaySize . x = screen_width ;
ImGui : : GetIO ( ) . DisplaySize . y = screen_height ;
2019-02-06 18:57:13 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2020-12-02 13:40:50 +00:00
UpdateInputState ( ) ;
2019-02-07 15:59:24 +00:00
2019-02-06 18:57:13 +00:00
// Read keyboard modifiers inputs
2021-04-29 16:58:04 +00:00
io . KeyCtrl = ( kb_shift [ 0 ] & ( 0x01 | 0x10 ) ) ! = 0 ;
io . KeyShift = ( kb_shift [ 0 ] & ( 0x02 | 0x20 ) ) ! = 0 ;
2019-02-06 18:57:13 +00:00
io . KeyAlt = false ;
io . KeySuper = false ;
memset ( & io . KeysDown [ 0 ] , 0 , sizeof ( io . KeysDown ) ) ;
2021-04-29 16:58:04 +00:00
for ( int i = 0 ; i < IM_ARRAYSIZE ( kb_key [ 0 ] ) ; i + + )
if ( kb_key [ 0 ] [ i ] ! = 0 )
io . KeysDown [ kb_key [ 0 ] [ i ] ] = true ;
2019-02-06 18:57:13 +00:00
else
break ;
2021-04-29 16:58:04 +00:00
if ( mouseX < 0 | | mouseX > = screen_width | | mouseY < 0 | | mouseY > = screen_height )
2019-02-06 18:57:13 +00:00
io . MousePos = ImVec2 ( - FLT_MAX , - FLT_MAX ) ;
else
2021-06-07 18:53:31 +00:00
io . MousePos = ImVec2 ( mouseX , mouseY ) ;
2021-06-04 09:11:23 +00:00
static bool delayTouch ;
2021-08-06 08:30:30 +00:00
# if defined(__ANDROID__) || defined(TARGET_IPHONE)
2021-06-04 09:11:23 +00:00
// Delay touch by one frame to allow widgets to be hovered before click
// This is required for widgets using ImGuiButtonFlags_AllowItemOverlap such as TabItem's
2021-06-07 18:53:31 +00:00
if ( ! delayTouch & & ( mouseButtons & ( 1 < < 0 ) ) ! = 0 & & ! io . MouseDown [ ImGuiMouseButton_Left ] )
2021-06-04 09:11:23 +00:00
delayTouch = true ;
2020-11-25 12:54:27 +00:00
else
2021-06-04 09:11:23 +00:00
delayTouch = false ;
2019-02-06 18:57:13 +00:00
# endif
2019-02-25 16:52:53 +00:00
if ( io . WantCaptureMouse )
{
2021-04-29 16:58:04 +00:00
io . MouseWheel = - mouseWheel / 16 ;
mouseWheel = 0 ;
2019-02-25 16:52:53 +00:00
}
2021-06-04 09:11:23 +00:00
if ( ! delayTouch )
2021-06-07 18:53:31 +00:00
io . MouseDown [ ImGuiMouseButton_Left ] = ( mouseButtons & ( 1 < < 0 ) ) ! = 0 ;
io . MouseDown [ ImGuiMouseButton_Right ] = ( mouseButtons & ( 1 < < 1 ) ) ! = 0 ;
io . MouseDown [ ImGuiMouseButton_Middle ] = ( mouseButtons & ( 1 < < 2 ) ) ! = 0 ;
2021-04-29 16:58:04 +00:00
io . MouseDown [ 3 ] = ( mouseButtons & ( 1 < < 3 ) ) ! = 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
2021-06-07 10:18:05 +00:00
ImGui : : GetStyle ( ) . Colors [ ImGuiCol_ModalWindowDimBg ] = ImVec4 ( 0.06f , 0.06f , 0.06f , 0.94f ) ;
2019-02-06 18:57:13 +00:00
}
2021-05-02 09:31:44 +00:00
void gui_set_insets ( int left , int right , int top , int bottom )
{
insetLeft = left ;
insetRight = right ;
insetTop = top ;
insetBottom = bottom ;
}
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
void gui_open_settings ( )
{
2021-03-01 09:13:40 +00:00
if ( gui_state = = GuiState : : Closed )
2019-02-06 18:57:13 +00:00
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Commands ;
2019-02-13 19:29:49 +00:00
HideOSD ( ) ;
2019-02-06 18:57:13 +00:00
}
2021-03-01 09:13:40 +00:00
else if ( gui_state = = GuiState : : VJoyEdit )
2019-03-04 23:54:01 +00:00
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : VJoyEditCommands ;
2019-03-04 23:54:01 +00:00
}
2021-03-01 09:13:40 +00:00
else if ( gui_state = = GuiState : : Loading )
2020-04-22 17:11:49 +00:00
{
dc_cancel_load ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Main ;
2020-04-22 17:11:49 +00:00
}
2021-03-01 09:13:40 +00:00
else if ( gui_state = = GuiState : : Commands )
2020-04-22 17:11:49 +00:00
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2021-06-27 10:49:47 +00:00
GamepadDevice : : load_system_mappings ( ) ;
2020-04-22 17:11:49 +00:00
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 ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Loading ;
2020-04-20 16:52:02 +00:00
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
}
2021-08-03 08:05:09 +00:00
void gui_stop_game ( const std : : string & message )
{
if ( ! commandLineStart )
{
// Exit to main menu
dc_term_game ( ) ;
gui_state = GuiState : : Main ;
game_started = false ;
settings . imgread . ImagePath [ 0 ] = ' \0 ' ;
reset_vmus ( ) ;
if ( ! message . empty ( ) )
error_msg = " Flycast has stopped. \n \n " + message ;
}
else
{
// Exit emulator
dc_exit ( ) ;
}
}
2019-02-06 18:57:13 +00:00
static void gui_display_commands ( )
{
2021-07-20 08:06:44 +00:00
if ( dc_is_running ( ) )
dc_stop ( ) ;
2019-02-06 18:57:13 +00:00
2021-04-06 09:41:04 +00:00
display_vmus ( ) ;
2019-03-29 16:35:00 +00:00
2021-04-06 09:41:04 +00:00
centerNextWindow ( ) ;
2019-02-06 18:57:13 +00:00
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
2021-03-19 18:31:01 +00:00
if ( settings . imgread . ImagePath [ 0 ] = = ' \0 ' )
{
ImGui : : PushItemFlag ( ImGuiItemFlags_Disabled , true ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , ImGui : : GetStyle ( ) . Alpha * 0.5f ) ;
}
2021-06-03 11:50:40 +00:00
if ( ImGui : : Button ( " Load State " , ImVec2 ( 110 * scaling , 50 * scaling ) ) )
2019-02-06 18:57:13 +00:00
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2021-06-03 11:50:40 +00:00
dc_loadstate ( config : : SavestateSlot ) ;
2019-02-06 18:57:13 +00:00
}
2021-06-03 11:50:40 +00:00
ImGui : : SameLine ( ) ;
std : : string slot = " Slot " + std : : to_string ( ( int ) config : : SavestateSlot + 1 ) ;
if ( ImGui : : Button ( slot . c_str ( ) , ImVec2 ( 80 * scaling - ImGui : : GetStyle ( ) . FramePadding . x , 50 * scaling ) ) )
ImGui : : OpenPopup ( " slot_select_popup " ) ;
if ( ImGui : : BeginPopup ( " slot_select_popup " ) )
{
for ( int i = 0 ; i < 10 ; i + + )
if ( ImGui : : Selectable ( std : : to_string ( i + 1 ) . c_str ( ) , config : : SavestateSlot = = i , 0 ,
ImVec2 ( ImGui : : CalcTextSize ( " Slot 8 " ) . x , 0 ) ) ) {
config : : SavestateSlot = i ;
SaveSettings ( ) ;
}
ImGui : : EndPopup ( ) ;
}
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Save State " , ImVec2 ( 110 * scaling , 50 * scaling ) ) )
2019-02-06 18:57:13 +00:00
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2021-06-03 11:50:40 +00:00
dc_savestate ( config : : SavestateSlot ) ;
2019-02-06 18:57:13 +00:00
}
2021-03-19 18:31:01 +00:00
if ( settings . imgread . ImagePath [ 0 ] = = ' \0 ' )
{
ImGui : : PopItemFlag ( ) ;
ImGui : : PopStyleVar ( ) ;
}
2019-02-06 18:57:13 +00:00
2021-06-03 11:50:40 +00:00
ImGui : : Columns ( 2 , " buttons " , false ) ;
2019-02-06 18:57:13 +00:00
if ( ImGui : : Button ( " Settings " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Settings ;
2019-02-06 18:57:13 +00:00
}
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Resume " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
2021-06-27 10:49:47 +00:00
GamepadDevice : : load_system_mappings ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2019-02-06 18:57:13 +00:00
}
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 )
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : SelectDisk ;
2020-01-30 17:59:26 +00:00
}
else
{
DiscOpenLid ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2020-01-30 17:59:26 +00:00
}
2019-02-06 18:57:13 +00:00
}
ImGui : : NextColumn ( ) ;
2021-04-06 09:41:04 +00:00
if ( ImGui : : Button ( " Cheats " , ImVec2 ( 150 * scaling , 50 * scaling ) ) )
{
gui_state = GuiState : : Cheats ;
}
ImGui : : Columns ( 1 , nullptr , false ) ;
if ( ImGui : : Button ( " Exit " , ImVec2 ( 300 * scaling + ImGui : : GetStyle ( ) . ColumnsMinSpacing + ImGui : : GetStyle ( ) . FramePadding . x * 2 - 1 ,
50 * scaling ) ) )
2019-02-06 18:57:13 +00:00
{
2021-08-03 08:05:09 +00:00
gui_stop_game ( ) ;
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
}
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 ] ;
}
}
2020-11-21 16:57:23 +00:00
const char * maple_ports [ ] = { " None " , " A " , " B " , " C " , " D " , " All " } ;
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-12-02 13:40:50 +00:00
DC_BTN_RELOAD ,
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-12-02 13:40:50 +00:00
" Reload " ,
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-12-02 13:40:50 +00:00
" Service " , " Coin " , " Test " , " Button 5 " , " Button 6 " , " Button 7 " , " Button 8 " ,
" Reload " ,
" N/A " , " N/A " , " N/A " , " N/A "
2020-04-17 15:55:43 +00:00
} ;
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 ;
2020-11-21 16:57:23 +00:00
static u32 gamepad_port ;
2019-02-12 10:30:24 +00:00
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 )
{
2020-11-21 16:57:23 +00:00
u32 previous_mapping = input_mapping - > get_axis_code ( gamepad_port , axis_keys [ index ] ) ;
2019-02-21 16:57:51 +00:00
bool inverted = false ;
2020-03-12 15:09:05 +00:00
if ( previous_mapping ! = ( u32 ) - 1 )
2020-11-21 16:57:23 +00:00
inverted = input_mapping - > get_axis_inverted ( gamepad_port , previous_mapping ) ;
2019-02-21 16:57:51 +00:00
// FIXME Allow inverted to be set
2020-11-21 16:57:23 +00:00
input_mapping - > set_axis ( gamepad_port , axis_keys [ index ] , mapped_code , inverted ) ;
2019-02-21 16:57:51 +00:00
}
else
2020-11-21 16:57:23 +00:00
input_mapping - > set_button ( gamepad_port , 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 ) ;
}
2021-03-13 13:13:39 +00:00
static void controller_mapping_popup ( const std : : shared_ptr < GamepadDevice > & gamepad )
2019-02-12 16:57:11 +00:00
{
2021-06-07 10:18:05 +00:00
fullScreenWindow ( true ) ;
2019-02-17 23:25:06 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0 ) ;
2021-06-07 10:18:05 +00:00
if ( ImGui : : BeginPopupModal ( " Controller Mapping " , NULL , ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
2019-02-12 16:57:11 +00:00
{
2021-06-07 10:18:05 +00:00
const ImGuiStyle & style = ImGui : : GetStyle ( ) ;
const float width = ( ImGui : : GetIO ( ) . DisplaySize . x - insetLeft - insetRight - style . ItemSpacing . x ) / 2 - style . WindowBorderSize - style . WindowPadding . x ;
const float col_width = ( width - style . GrabMinSize - style . ItemSpacing . x
2021-06-27 10:49:47 +00:00
- ( ImGui : : CalcTextSize ( " Map " ) . x + style . FramePadding . x * 2.0f + style . ItemSpacing . x )
- ( ImGui : : CalcTextSize ( " Unmap " ) . x + style . FramePadding . x * 2.0f + style . ItemSpacing . x ) ) / 2 ;
2019-02-12 16:57:11 +00:00
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 ( ) ;
2021-06-27 10:49:47 +00:00
gamepad - > save_mapping ( map_system ) ;
2019-02-12 16:57:11 +00:00
}
ImGui : : SetItemDefaultFocus ( ) ;
2020-11-21 16:57:23 +00:00
if ( gamepad - > maple_port ( ) = = MAPLE_PORTS )
{
ImGui : : SameLine ( ) ;
float w = ImGui : : CalcItemWidth ( ) ;
ImGui : : PushItemWidth ( w / 2 ) ;
if ( ImGui : : BeginCombo ( " Port " , maple_ports [ gamepad_port + 1 ] ) )
{
for ( u32 j = 0 ; j < MAPLE_PORTS ; j + + )
{
bool is_selected = gamepad_port = = j ;
if ( ImGui : : Selectable ( maple_ports [ j + 1 ] , & is_selected ) )
gamepad_port = j ;
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
}
ImGui : : EndCombo ( ) ;
}
ImGui : : PopItemWidth ( ) ;
}
2021-06-27 10:49:47 +00:00
ImGui : : SameLine ( ImGui : : GetContentRegionAvail ( ) . x - ImGui : : CalcTextSize ( " Dreamcast Controls " ) . x
- ImGui : : GetStyle ( ) . FramePadding . x * 3.0f - ImGui : : GetStyle ( ) . ItemSpacing . x * 3.0f ) ;
ImGui : : AlignTextToFramePadding ( ) ;
2021-07-20 17:21:11 +00:00
2021-06-27 10:49:47 +00:00
const char * items [ ] = { " Dreamcast Controls " , " Arcade Controls " } ;
static int item_current_map_idx = 0 ;
static int last_item_current_map_idx = 2 ;
// Here our selection data is an index.
ImGui : : PushItemWidth ( ImGui : : CalcTextSize ( " Dreamcast Controls " ) . x + ImGui : : GetStyle ( ) . ItemSpacing . x * 2.0f * 3 ) ;
ImGui : : Combo ( " " , & item_current_map_idx , items , IM_ARRAYSIZE ( items ) ) ;
if ( item_current_map_idx ! = last_item_current_map_idx )
{
gamepad - > save_mapping ( map_system ) ;
}
if ( item_current_map_idx = = 0 )
{
arcade_button_mode = false ;
map_system = DC_PLATFORM_DREAMCAST ;
}
else if ( item_current_map_idx = = 1 )
{
arcade_button_mode = true ;
map_system = DC_PLATFORM_NAOMI ;
}
if ( item_current_map_idx ! = last_item_current_map_idx )
{
gamepad - > find_mapping ( map_system ) ;
input_mapping = gamepad - > get_input_mapping ( ) ;
last_item_current_map_idx = item_current_map_idx ;
}
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 ) ;
2020-12-02 13:40:50 +00:00
ImGui : : SetColumnWidth ( 0 , col_width ) ;
ImGui : : SetColumnWidth ( 1 , col_width ) ;
2021-06-27 10:49:47 +00:00
gamepad - > find_mapping ( map_system ) ;
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-12-02 13:40:50 +00:00
const char * btn_name = arcade_button_mode ? arcade_button_names [ j ] : button_names [ j ] ;
const char * game_btn_name = GetCurrentGameButtonName ( button_keys [ j ] ) ;
if ( game_btn_name ! = nullptr )
ImGui : : Text ( " %s - %s " , btn_name , game_btn_name ) ;
else
ImGui : : Text ( " %s " , btn_name ) ;
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
2020-11-21 16:57:23 +00:00
u32 code = input_mapping - > get_button_code ( gamepad_port , button_keys [ j ] ) ;
2020-03-12 15:09:05 +00:00
if ( code ! = ( u32 ) - 1 )
2020-11-20 21:10:14 +00:00
{
const char * label = gamepad - > get_button_name ( code ) ;
if ( label ! = nullptr )
ImGui : : Text ( " %s " , label ) ;
else
ImGui : : Text ( " [%d] " , code ) ;
}
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Map " ) )
{
map_start_time = os_GetSeconds ( ) ;
ImGui : : OpenPopup ( " Map Button " ) ;
mapped_device = gamepad ;
mapped_code = - 1 ;
2021-04-06 09:41:04 +00:00
gamepad - > detect_btn_input ( [ ] ( u32 code )
{
mapped_code = code ;
} ) ;
2019-02-12 16:57:11 +00:00
}
detect_input_popup ( j , false ) ;
2021-06-27 10:49:47 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Unmap " ) )
{
input_mapping = gamepad - > get_input_mapping ( ) ;
input_mapping - > clear_button ( gamepad_port , button_keys [ j ] , j ) ;
}
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
2021-06-07 10:18:05 +00:00
ImGui : : Columns ( 1 , nullptr , false ) ;
scrollWhenDraggingOnVoid ( ) ;
windowDragScroll ( ) ;
2019-02-12 16:57:11 +00:00
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 ) ;
2021-06-07 10:18:05 +00:00
ImGui : : Columns ( 3 , " anabindings " , false ) ;
2020-12-02 13:40:50 +00:00
ImGui : : SetColumnWidth ( 0 , col_width ) ;
ImGui : : SetColumnWidth ( 1 , col_width ) ;
2019-02-12 16:57:11 +00:00
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-12-02 13:40:50 +00:00
const char * axis_name = arcade_button_mode ? arcade_axis_names [ j ] : axis_names [ j ] ;
const char * game_axis_name = GetCurrentGameAxisName ( axis_keys [ j ] ) ;
if ( game_axis_name ! = nullptr )
ImGui : : Text ( " %s - %s " , axis_name , game_axis_name ) ;
else
ImGui : : Text ( " %s " , axis_name ) ;
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
2020-11-21 16:57:23 +00:00
u32 code = input_mapping - > get_axis_code ( gamepad_port , axis_keys [ j ] ) ;
2020-03-12 15:09:05 +00:00
if ( code ! = ( u32 ) - 1 )
2020-11-20 21:10:14 +00:00
{
const char * label = gamepad - > get_axis_name ( code ) ;
if ( label ! = nullptr )
ImGui : : Text ( " %s " , label ) ;
else
ImGui : : Text ( " [%d] " , code ) ;
}
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
if ( ImGui : : Button ( " Map " ) )
{
map_start_time = os_GetSeconds ( ) ;
ImGui : : OpenPopup ( " Map Axis " ) ;
mapped_device = gamepad ;
mapped_code = - 1 ;
2021-04-06 09:41:04 +00:00
gamepad - > detect_axis_input ( [ ] ( u32 code )
{
mapped_code = code ;
} ) ;
2019-02-12 16:57:11 +00:00
}
detect_input_popup ( j , true ) ;
2021-06-27 10:49:47 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Unmap " ) )
{
input_mapping = gamepad - > get_input_mapping ( ) ;
input_mapping - > clear_axis ( gamepad_port , axis_keys [ j ] , j ) ;
}
2019-02-12 16:57:11 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
2021-06-07 10:18:05 +00:00
ImGui : : Columns ( 1 , nullptr , false ) ;
scrollWhenDraggingOnVoid ( ) ;
windowDragScroll ( ) ;
2019-02-12 16:57:11 +00:00
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 ( ) )
{
2021-08-03 08:05:09 +00:00
ImVec2 padding = ImVec2 ( 20 * scaling , 20 * scaling ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , padding ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_ItemSpacing , padding ) ;
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 ) ) ;
2020-11-25 12:54:27 +00:00
float currentwidth = ImGui : : GetContentRegionAvail ( ) . x ;
2019-03-04 23:54:01 +00:00
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 ( ) ;
2021-08-03 08:05:09 +00:00
ImGui : : PopTextWrapPos ( ) ;
2019-03-04 23:54:01 +00:00
ImGui : : EndPopup ( ) ;
}
2021-08-03 08:05:09 +00:00
ImGui : : PopStyleVar ( ) ;
ImGui : : PopStyleVar ( ) ;
2019-03-04 23:54:01 +00:00
}
}
2020-11-03 21:40:20 +00:00
static void contentpath_warning_popup ( )
{
2020-11-25 09:20:03 +00:00
static bool show_contentpath_selection ;
if ( scanner . content_path_looks_incorrect )
2020-11-03 21:40:20 +00:00
{
ImGui : : OpenPopup ( " Incorrect Content Location? " ) ;
if ( ImGui : : BeginPopupModal ( " Incorrect Content Location? " , NULL , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove ) )
{
ImGui : : PushTextWrapPos ( ImGui : : GetCursorPos ( ) . x + 400.f * scaling ) ;
2020-11-25 09:20:03 +00:00
ImGui : : TextWrapped ( " Scanned %d folders but no game can be found! " , scanner . empty_folders_scanned ) ;
2020-11-03 21:40:20 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 16 * scaling , 3 * scaling ) ) ;
2020-11-25 12:54:27 +00:00
float currentwidth = ImGui : : GetContentRegionAvail ( ) . x ;
2020-11-03 21:40:20 +00:00
ImGui : : SetCursorPosX ( ( currentwidth - 100.f * scaling ) / 2.f + ImGui : : GetStyle ( ) . WindowPadding . x - 55.f * scaling ) ;
if ( ImGui : : Button ( " Reselect " , ImVec2 ( 100.f * scaling , 0.f ) ) )
{
2020-11-25 09:20:03 +00:00
scanner . content_path_looks_incorrect = false ;
2020-11-03 21:40:20 +00:00
ImGui : : CloseCurrentPopup ( ) ;
show_contentpath_selection = true ;
}
ImGui : : SameLine ( ) ;
ImGui : : SetCursorPosX ( ( currentwidth - 100.f * scaling ) / 2.f + ImGui : : GetStyle ( ) . WindowPadding . x + 55.f * scaling ) ;
if ( ImGui : : Button ( " Cancel " , ImVec2 ( 100.f * scaling , 0.f ) ) )
{
2020-11-25 09:20:03 +00:00
scanner . content_path_looks_incorrect = false ;
2020-11-03 21:40:20 +00:00
ImGui : : CloseCurrentPopup ( ) ;
2020-11-25 09:20:03 +00:00
scanner . stop ( ) ;
2021-03-01 09:13:40 +00:00
config : : ContentPath . get ( ) . clear ( ) ;
2020-11-03 21:40:20 +00:00
}
ImGui : : SetItemDefaultFocus ( ) ;
ImGui : : PopStyleVar ( ) ;
ImGui : : EndPopup ( ) ;
}
}
if ( show_contentpath_selection )
{
2020-11-03 21:59:25 +00:00
scanner . stop ( ) ;
2020-11-03 21:40:20 +00:00
ImGui : : OpenPopup ( " Select Directory " ) ;
2021-04-06 09:41:04 +00:00
select_file_popup ( " Select Directory " , [ ] ( bool cancelled , std : : string selection )
2020-11-03 21:40:20 +00:00
{
show_contentpath_selection = false ;
if ( ! cancelled )
{
2021-03-01 09:13:40 +00:00
config : : ContentPath . get ( ) . clear ( ) ;
config : : ContentPath . get ( ) . push_back ( selection ) ;
2020-11-03 21:59:25 +00:00
}
2020-11-25 09:20:03 +00:00
scanner . refresh ( ) ;
2020-11-03 21:40:20 +00:00
} ) ;
}
}
2021-06-07 10:18:05 +00:00
inline static void header ( const char * title )
{
ImGui : : PushStyleVar ( ImGuiStyleVar_ButtonTextAlign , ImVec2 ( 0.f , 0.5f ) ) ; // Left
ImGui : : ButtonEx ( title , ImVec2 ( - 1 , 0 ) , ImGuiButtonFlags_Disabled ) ;
ImGui : : PopStyleVar ( ) ;
}
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 ;
2021-06-07 10:18:05 +00:00
fullScreenWindow ( false ) ;
2019-02-20 22:22:58 +00:00
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 )
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Commands ;
2019-02-25 16:52:53 +00:00
else
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : 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 ) ) ;
2021-03-01 09:13:40 +00:00
if ( config : : Settings : : instance ( ) . hasPerGameConfig ( ) )
2019-02-25 16:52:53 +00:00
{
if ( ImGui : : Button ( " Delete Game Config " , ImVec2 ( 0 , 30 * scaling ) ) )
{
2021-03-01 09:13:40 +00:00
config : : Settings : : instance ( ) . setPerGameConfig ( false ) ;
config : : Settings : : instance ( ) . load ( false ) ;
2021-07-05 17:44:08 +00:00
loadGameSpecificSettings ( ) ;
2019-02-25 16:52:53 +00:00
}
}
else
{
if ( ImGui : : Button ( " Make Game Config " , ImVec2 ( 0 , 30 * scaling ) ) )
2021-03-01 09:13:40 +00:00
config : : Settings : : instance ( ) . setPerGameConfig ( true ) ;
2019-02-25 16:52:53 +00:00
}
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 " } ;
2021-03-01 09:13:40 +00:00
OptionComboBox ( " Language " , config : : Language , languages , ARRAY_SIZE ( languages ) ,
" 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 " } ;
2021-03-01 09:13:40 +00:00
OptionComboBox ( " Broadcast " , config : : Broadcast , broadcast , ARRAY_SIZE ( broadcast ) ,
" TV broadcasting standard for non-VGA modes " ) ;
2019-02-06 18:57:13 +00:00
const char * region [ ] = { " Japan " , " USA " , " Europe " , " Default " } ;
2021-03-01 09:13:40 +00:00
OptionComboBox ( " Region " , config : : Region , region , ARRAY_SIZE ( region ) ,
" 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 " } ;
2021-03-01 09:13:40 +00:00
if ( config : : Cable . isReadOnly ( ) )
{
ImGui : : PushItemFlag ( ImGuiItemFlags_Disabled , true ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , ImGui : : GetStyle ( ) . Alpha * 0.5f ) ;
}
if ( ImGui : : BeginCombo ( " Cable " , cable [ config : : Cable = = 0 ? 0 : config : : Cable - 1 ] , ImGuiComboFlags_None ) )
2019-02-06 18:57:13 +00:00
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( cable ) ; i + + )
{
2021-03-01 09:13:40 +00:00
bool is_selected = i = = 0 ? config : : Cable < = 1 : config : : Cable - 1 = = i ;
2019-02-06 18:57:13 +00:00
if ( ImGui : : Selectable ( cable [ i ] , & is_selected ) )
2021-03-01 09:13:40 +00:00
config : : Cable = i = = 0 ? 0 : i + 1 ;
2019-02-09 20:20:03 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
2019-02-06 18:57:13 +00:00
}
ImGui : : EndCombo ( ) ;
}
2021-03-01 09:13:40 +00:00
if ( config : : Cable . isReadOnly ( ) )
{
ImGui : : PopItemFlag ( ) ;
ImGui : : PopStyleVar ( ) ;
}
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
ImVec2 size ;
size . x = 0.0f ;
size . y = ( ImGui : : GetTextLineHeightWithSpacing ( ) + ImGui : : GetStyle ( ) . FramePadding . y * 2.f )
2021-03-01 09:13:40 +00:00
* ( config : : ContentPath . get ( ) . size ( ) + 1 ) ; //+ ImGui::GetStyle().FramePadding.y * 2.f;
2019-02-25 16:52:53 +00:00
if ( ImGui : : ListBoxHeader ( " Content Location " , size ) )
{
int to_delete = - 1 ;
2021-03-01 09:13:40 +00:00
for ( u32 i = 0 ; i < config : : ContentPath . get ( ) . size ( ) ; i + + )
2019-02-25 16:52:53 +00:00
{
2021-03-01 09:13:40 +00:00
ImGui : : PushID ( config : : ContentPath . get ( ) [ i ] . c_str ( ) ) ;
2019-02-25 16:52:53 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2021-03-01 09:13:40 +00:00
ImGui : : Text ( " %s " , config : : ContentPath . get ( ) [ i ] . c_str ( ) ) ;
2020-11-25 12:54:27 +00:00
ImGui : : SameLine ( ImGui : : GetContentRegionAvail ( ) . x - ImGui : : CalcTextSize ( " X " ) . x - ImGui : : GetStyle ( ) . FramePadding . x ) ;
2019-02-25 16:52:53 +00:00
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 " ) ;
2021-04-06 09:41:04 +00:00
select_file_popup ( " Select Directory " , [ ] ( bool cancelled , std : : string selection )
{
if ( ! cancelled )
{
scanner . stop ( ) ;
config : : ContentPath . get ( ) . push_back ( selection ) ;
scanner . refresh ( ) ;
}
} ) ;
2020-03-12 15:09:05 +00:00
ImGui : : PopStyleVar ( ) ;
2021-06-07 10:18:05 +00:00
scrollWhenDraggingOnVoid ( ) ;
2019-02-25 16:52:53 +00:00
ImGui : : ListBoxFooter ( ) ;
if ( to_delete > = 0 )
{
2020-11-25 09:20:03 +00:00
scanner . stop ( ) ;
2021-03-01 09:13:40 +00:00
config : : ContentPath . get ( ) . erase ( config : : ContentPath . get ( ) . 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 " ) ;
2021-04-19 17:12:00 +00:00
# ifdef __linux__
if ( ImGui : : ListBoxHeader ( " Data Directory " , 1 ) )
{
ImGui : : AlignTextToFramePadding ( ) ;
ImGui : : Text ( " %s " , get_writable_data_path ( " " ) . c_str ( ) ) ;
ImGui : : ListBoxFooter ( ) ;
}
ImGui : : SameLine ( ) ;
ShowHelpMarker ( " The directory containing BIOS files, as well as saved VMUs and states " ) ;
# else
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__
2020-11-25 12:54:27 +00:00
ImGui : : SameLine ( ImGui : : GetContentRegionAvail ( ) . x - ImGui : : CalcTextSize ( " Change " ) . x - ImGui : : GetStyle ( ) . FramePadding . x ) ;
2019-03-05 11:45:11 +00:00
if ( ImGui : : Button ( " Change " ) )
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Onboarding ;
2019-03-05 11:45:11 +00:00
# endif
ImGui : : ListBoxFooter ( ) ;
}
ImGui : : SameLine ( ) ;
2021-03-16 09:15:23 +00:00
ShowHelpMarker ( " The directory where Flycast saves configuration files and VMUs. BIOS files should be in a subfolder named \" data \" " ) ;
2021-04-19 17:12:00 +00:00
# endif
2021-03-01 09:13:40 +00:00
if ( OptionCheckbox ( " Hide Legacy Naomi Roms " , config : : HideLegacyNaomiRoms ,
" Hide .bin, .dat and .lst files from the content browser " ) )
scanner . refresh ( ) ;
2021-06-04 09:11:23 +00:00
ImGui : : Text ( " Automatic State: " ) ;
OptionCheckbox ( " Load " , config : : AutoLoadState ,
" Load the last saved state of the game when starting " ) ;
ImGui : : SameLine ( ) ;
OptionCheckbox ( " Save " , config : : AutoSaveState ,
" Save the state of the game when stopping " ) ;
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 ) ;
2021-06-07 10:18:05 +00:00
header ( " Physical Devices " ) ;
{
ImGui : : Columns ( 4 , " physicalDevices " , 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 + + )
{
std : : shared_ptr < GamepadDevice > gamepad = GamepadDevice : : GetGamepad ( i ) ;
if ( ! gamepad )
continue ;
ImGui : : Text ( " %s " , gamepad - > api_name ( ) . c_str ( ) ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " %s " , gamepad - > name ( ) . c_str ( ) ) ;
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 < ( int ) ARRAY_SIZE ( maple_ports ) - 1 ; 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 ( ) ;
if ( gamepad - > remappable ( ) & & ImGui : : Button ( " Map " ) )
{
gamepad_port = 0 ;
2021-06-27 10:49:47 +00:00
gamepad - > verify_or_create_system_mappings ( ) ;
2021-06-07 10:18:05 +00:00
ImGui : : OpenPopup ( " Controller Mapping " ) ;
}
controller_mapping_popup ( gamepad ) ;
# ifdef __ANDROID__
if ( gamepad - > is_virtual_gamepad ( ) )
{
if ( ImGui : : Button ( " Edit " ) )
{
vjoy_start_editing ( ) ;
gui_state = GuiState : : VJoyEdit ;
}
ImGui : : SameLine ( ) ;
OptionSlider ( " Haptic " , config : : VirtualGamepadVibration , 0 , 60 ) ;
}
# endif
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
}
ImGui : : Columns ( 1 , NULL , false ) ;
ImGui : : Spacing ( ) ;
OptionSlider ( " Mouse sensitivity " , config : : MouseSensitivity , 1 , 500 ) ;
2021-06-07 18:53:31 +00:00
# ifdef _WIN32
OptionCheckbox ( " Use Raw Input " , config : : UseRawInput , " Supports multiple pointing devices (mice, light guns) and keyboards " ) ;
# endif
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Dreamcast Devices " ) ;
2019-02-12 10:30:24 +00:00
{
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 ) ;
2021-03-01 09:13:40 +00:00
if ( ImGui : : BeginCombo ( device_name , maple_device_name ( config : : MapleMainDevices [ bus ] ) , ImGuiComboFlags_None ) )
2019-02-12 10:30:24 +00:00
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( maple_device_types ) ; i + + )
{
2021-03-01 09:13:40 +00:00
bool is_selected = config : : MapleMainDevices [ bus ] = = maple_device_type_from_index ( i ) ;
2019-02-12 10:30:24 +00:00
if ( ImGui : : Selectable ( maple_device_types [ i ] , & is_selected ) )
2019-04-08 13:54:37 +00:00
{
2021-03-01 09:13:40 +00:00
config : : MapleMainDevices [ 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 ( ) ;
}
2021-03-01 09:13:40 +00:00
int port_count = config : : MapleMainDevices [ bus ] = = MDT_SegaController ? 2
: config : : MapleMainDevices [ bus ] = = MDT_LightGun | | config : : MapleMainDevices [ bus ] = = MDT_TwinStick | | config : : MapleMainDevices [ bus ] = = MDT_AsciiStick ? 1
2019-07-12 17:18:39 +00:00
: 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 ) ;
2021-03-01 09:13:40 +00:00
if ( ImGui : : BeginCombo ( device_name , maple_expansion_device_name ( config : : MapleExpansionDevices [ bus ] [ port ] ) , ImGuiComboFlags_None ) )
2019-02-12 10:30:24 +00:00
{
for ( int i = 0 ; i < IM_ARRAYSIZE ( maple_expansion_device_types ) ; i + + )
{
2021-03-01 09:13:40 +00:00
bool is_selected = config : : MapleExpansionDevices [ bus ] [ port ] = = maple_expansion_device_type_from_index ( i ) ;
2019-02-12 10:30:24 +00:00
if ( ImGui : : Selectable ( maple_expansion_device_types [ i ] , & is_selected ) )
2019-04-08 13:54:37 +00:00
{
2021-03-01 09:13:40 +00:00
config : : MapleExpansionDevices [ 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 ( ) ;
}
2021-03-01 09:13:40 +00:00
if ( config : : MapleMainDevices [ bus ] = = MDT_LightGun )
2021-01-23 14:59:57 +00:00
{
ImGui : : SameLine ( ) ;
sprintf ( device_name , " ##device%d.xhair " , bus ) ;
ImGui : : PushID ( device_name ) ;
2021-03-01 09:13:40 +00:00
u32 color = config : : CrosshairColor [ bus ] ;
2021-01-23 14:59:57 +00:00
float xhairColor [ 4 ] {
( color & 0xff ) / 255.f ,
( ( color > > 8 ) & 0xff ) / 255.f ,
( ( color > > 16 ) & 0xff ) / 255.f ,
( ( color > > 24 ) & 0xff ) / 255.f
} ;
ImGui : : ColorEdit4 ( " Crosshair color " , xhairColor , ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_AlphaPreviewHalf
| ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoLabel ) ;
ImGui : : SameLine ( ) ;
bool enabled = color ! = 0 ;
ImGui : : Checkbox ( " Crosshair " , & enabled ) ;
if ( enabled )
{
2021-03-01 09:13:40 +00:00
config : : CrosshairColor [ bus ] = ( u8 ) ( xhairColor [ 0 ] * 255.f )
2021-01-23 14:59:57 +00:00
| ( ( u8 ) ( xhairColor [ 1 ] * 255.f ) < < 8 )
| ( ( u8 ) ( xhairColor [ 2 ] * 255.f ) < < 16 )
| ( ( u8 ) ( xhairColor [ 3 ] * 255.f ) < < 24 ) ;
2021-03-01 09:13:40 +00:00
if ( config : : CrosshairColor [ bus ] = = 0 )
config : : CrosshairColor [ bus ] = 0xC0FFFFFF ;
2021-01-23 14:59:57 +00:00
}
else
{
2021-03-01 09:13:40 +00:00
config : : CrosshairColor [ bus ] = 0 ;
2021-01-23 14:59:57 +00:00
}
ImGui : : PopID ( ) ;
}
2019-02-12 10:30:24 +00:00
ImGui : : PopItemWidth ( ) ;
}
}
2019-02-09 20:20:03 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-06 18:57:13 +00:00
ImGui : : EndTabItem ( ) ;
}
if ( ImGui : : BeginTabItem ( " Video " ) )
{
2021-04-12 20:49:04 +00:00
int renderApi ;
bool perPixel ;
switch ( config : : RendererType )
{
default :
case RenderType : : OpenGL :
renderApi = 0 ;
perPixel = false ;
break ;
case RenderType : : OpenGL_OIT :
renderApi = 0 ;
perPixel = true ;
break ;
case RenderType : : Vulkan :
renderApi = 1 ;
perPixel = false ;
break ;
case RenderType : : Vulkan_OIT :
renderApi = 1 ;
perPixel = true ;
break ;
case RenderType : : DirectX9 :
renderApi = 2 ;
perPixel = false ;
break ;
}
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
2020-04-26 08:03:57 +00:00
# if !defined(__APPLE__)
2020-01-31 17:33:16 +00:00
bool has_per_pixel = false ;
2021-04-12 20:49:04 +00:00
if ( renderApi = = 0 )
2019-11-13 19:08:14 +00:00
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
2021-06-07 10:18:05 +00:00
header ( " Transparent Sorting " ) ;
2019-02-09 20:20:03 +00:00
{
2021-04-12 20:49:04 +00:00
int renderer = perPixel ? 2 : config : : 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 :
2021-04-12 20:49:04 +00:00
perPixel = false ;
2021-03-01 09:13:40 +00:00
config : : PerStripSorting . set ( false ) ;
2019-05-17 17:48:25 +00:00
break ;
case 1 :
2021-04-12 20:49:04 +00:00
perPixel = false ;
2021-03-01 09:13:40 +00:00
config : : PerStripSorting . set ( true ) ;
2019-05-17 17:48:25 +00:00
break ;
case 2 :
2021-04-12 20:49:04 +00:00
perPixel = true ;
2019-05-17 17:48:25 +00:00
break ;
}
2019-02-09 20:20:03 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Rendering Options " ) ;
2019-02-09 20:20:03 +00:00
{
2020-12-25 11:08:44 +00:00
ImGui : : Text ( " Automatic Frame Skipping: " ) ;
ImGui : : Columns ( 3 , " autoskip " , false ) ;
2021-03-01 09:13:40 +00:00
OptionRadioButton ( " Disabled " , config : : AutoSkipFrame , 0 , " No frame skipping " ) ;
2020-12-25 11:08:44 +00:00
ImGui : : NextColumn ( ) ;
2021-03-01 09:13:40 +00:00
OptionRadioButton ( " Normal " , config : : AutoSkipFrame , 1 , " Skip a frame when the GPU and CPU are both running slow " ) ;
2020-12-25 11:08:44 +00:00
ImGui : : NextColumn ( ) ;
2021-03-01 09:13:40 +00:00
OptionRadioButton ( " Maximum " , config : : AutoSkipFrame , 2 , " Skip a frame when the GPU is running slow " ) ;
2020-12-25 11:08:44 +00:00
ImGui : : Columns ( 1 , nullptr , false ) ;
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Shadows " , config : : ModifierVolumes ,
" Enable modifier volumes, usually used for shadows " ) ;
OptionCheckbox ( " Fog " , config : : Fog , " Enable fog effects " ) ;
OptionCheckbox ( " Widescreen " , config : : Widescreen ,
" Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas " ) ;
2021-04-20 14:06:03 +00:00
if ( ! config : : Widescreen )
{
ImGui : : PushItemFlag ( ImGuiItemFlags_Disabled , true ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , ImGui : : GetStyle ( ) . Alpha * 0.5f ) ;
}
ImGui : : Indent ( ) ;
OptionCheckbox ( " Super Widescreen " , config : : SuperWidescreen ,
" Use the full width of the screen or window when its aspect ratio is greater than 16:9 " ) ;
ImGui : : Unindent ( ) ;
if ( ! config : : Widescreen )
{
ImGui : : PopItemFlag ( ) ;
ImGui : : PopStyleVar ( ) ;
}
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Widescreen Game Cheats " , config : : WidescreenGameHacks ,
" Modify the game so that it displays in 16:9 anamorphic format and use horizontal screen stretching. Only some games are supported. " ) ;
2021-05-10 16:02:06 +00:00
# ifndef __APPLE__
OptionCheckbox ( " VSync " , config : : VSync , " Synchronizes the frame rate with the screen refresh rate. Recommended " ) ;
# endif
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Show FPS Counter " , config : : ShowFPS , " Show on-screen frame/sec counter " ) ;
OptionCheckbox ( " Show VMU In-game " , config : : FloatVMUs , " Show the VMU LCD screens while in-game " ) ;
OptionCheckbox ( " Rotate Screen 90° " , config : : Rotate90 , " Rotate the screen 90° counterclockwise " ) ;
OptionCheckbox ( " Delay Frame Swapping " , config : : DelayFrameSwapping ,
" Useful to avoid flashing screen or glitchy videos. Not recommended on slow platforms " ) ;
2021-04-12 20:49:04 +00:00
# if defined(USE_VULKAN) || defined(_WIN32)
ImGui : : Text ( " Graphics API: " ) ;
# if defined(USE_VULKAN) && defined(_WIN32)
constexpr u32 columns = 3 ;
# else
constexpr u32 columns = 2 ;
# endif
ImGui : : Columns ( columns , " renderApi " , false ) ;
ImGui : : RadioButton ( " Open GL " , & renderApi , 0 ) ;
ImGui : : NextColumn ( ) ;
2021-03-01 09:13:40 +00:00
# ifdef USE_VULKAN
2021-04-12 20:49:04 +00:00
ImGui : : RadioButton ( " Vulkan " , & renderApi , 1 ) ;
ImGui : : NextColumn ( ) ;
# endif
# ifdef _WIN32
ImGui : : RadioButton ( " DirectX " , & renderApi , 2 ) ;
ImGui : : NextColumn ( ) ;
# endif
ImGui : : Columns ( 1 , NULL , false ) ;
2021-03-01 09:13:40 +00:00
# endif
2021-04-12 20:49:04 +00:00
2021-03-19 18:31:01 +00:00
const std : : array < float , 9 > scalings { 0.5f , 1.f , 1.5f , 2.f , 2.5f , 3.f , 4.f , 4.5f , 5.f } ;
const std : : array < std : : string , 9 > scalingsText { " Half " , " Native " , " x1.5 " , " x2 " , " x2.5 " , " x3 " , " x4 " , " x4.5 " , " x5 " } ;
std : : array < int , scalings . size ( ) > vres ;
std : : array < std : : string , scalings . size ( ) > resLabels ;
u32 selected = 0 ;
for ( u32 i = 0 ; i < scalings . size ( ) ; i + + )
{
vres [ i ] = scalings [ i ] * 480 ;
if ( vres [ i ] = = config : : RenderResolution )
selected = i ;
if ( ! config : : Widescreen )
resLabels [ i ] = std : : to_string ( ( int ) ( scalings [ i ] * 640 ) ) + " x " + std : : to_string ( ( int ) ( scalings [ i ] * 480 ) ) ;
else
resLabels [ i ] = std : : to_string ( ( int ) ( scalings [ i ] * 480 * 16 / 9 ) ) + " x " + std : : to_string ( ( int ) ( scalings [ i ] * 480 ) ) ;
resLabels [ i ] + = " ( " + scalingsText [ i ] + " ) " ;
}
2020-01-29 19:26:09 +00:00
2021-06-07 10:18:05 +00:00
ImGuiStyle & style = ImGui : : GetStyle ( ) ;
float innerSpacing = style . ItemInnerSpacing . x ;
ImGui : : PushItemWidth ( ImGui : : CalcItemWidth ( ) - innerSpacing * 2.0f - ImGui : : GetFrameHeight ( ) * 2.0f ) ;
2021-03-19 18:31:01 +00:00
if ( ImGui : : BeginCombo ( " ##Resolution " , resLabels [ selected ] . c_str ( ) , ImGuiComboFlags_NoArrowButton ) )
2020-01-29 19:26:09 +00:00
{
2021-03-19 18:31:01 +00:00
for ( u32 i = 0 ; i < scalings . size ( ) ; i + + )
2020-01-31 17:33:16 +00:00
{
2021-03-19 18:31:01 +00:00
bool is_selected = vres [ i ] = = config : : RenderResolution ;
if ( ImGui : : Selectable ( resLabels [ i ] . c_str ( ) , is_selected ) )
config : : RenderResolution = vres [ i ] ;
2020-01-29 19:26:09 +00:00
if ( is_selected )
ImGui : : SetItemDefaultFocus ( ) ;
}
ImGui : : EndCombo ( ) ;
}
ImGui : : PopItemWidth ( ) ;
2021-06-07 10:18:05 +00:00
ImGui : : SameLine ( 0 , innerSpacing ) ;
2020-01-29 19:26:09 +00:00
2021-03-19 18:31:01 +00:00
if ( ImGui : : ArrowButton ( " ##Decrease Res " , ImGuiDir_Left ) )
2020-01-29 19:26:09 +00:00
{
2021-03-19 18:31:01 +00:00
if ( selected > 0 )
config : : RenderResolution = vres [ selected - 1 ] ;
2020-01-29 19:26:09 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : SameLine ( 0 , innerSpacing ) ;
2021-03-19 18:31:01 +00:00
if ( ImGui : : ArrowButton ( " ##Increase Res " , ImGuiDir_Right ) )
2020-01-29 19:26:09 +00:00
{
2021-03-19 18:31:01 +00:00
if ( selected < vres . size ( ) - 1 )
config : : RenderResolution = vres [ selected + 1 ] ;
2020-01-29 19:26:09 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : SameLine ( 0 , style . ItemInnerSpacing . x ) ;
2020-01-29 19:26:09 +00:00
2021-03-19 18:31:01 +00:00
ImGui : : Text ( " Internal Resolution " ) ;
2020-01-29 19:26:09 +00:00
ImGui : : SameLine ( ) ;
2021-03-19 18:31:01 +00:00
ShowHelpMarker ( " Internal render resolution. Higher is better but more demanding " ) ;
2020-01-29 19:26:09 +00:00
2021-03-01 09:13:40 +00:00
OptionSlider ( " Horizontal Stretching " , config : : ScreenStretching , 100 , 150 ,
" Stretch the screen horizontally " ) ;
2021-06-07 10:18:05 +00:00
OptionArrowButtons ( " Frame Skipping " , config : : SkipFrame , 0 , 6 ,
2021-03-01 09:13:40 +00:00
" Number of frames to skip between two actually rendered frames " ) ;
2019-02-09 20:20:03 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Render to Texture " ) ;
2019-02-09 20:20:03 +00:00
{
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Copy to VRAM " , config : : RenderToTextureBuffer ,
" Copy rendered-to textures back to VRAM. Slower but accurate " ) ;
2019-02-09 20:20:03 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Texture Upscaling " ) ;
2019-02-09 20:20:03 +00:00
{
2021-03-21 17:00:01 +00:00
# ifndef TARGET_NO_OPENMP
2021-06-07 10:18:05 +00:00
OptionArrowButtons ( " Texture Upscaling " , config : : TextureUpscale , 1 , 8 ,
2021-03-01 09:13:40 +00:00
" Upscale textures with the xBRZ algorithm. Only on fast platforms and for certain 2D games " ) ;
2021-06-07 10:18:05 +00:00
OptionSlider ( " Texture Max Size " , config : : MaxFilteredTextureSize , 8 , 1024 ,
2021-03-01 09:13:40 +00:00
" Textures larger than this dimension squared will not be upscaled " ) ;
2021-06-07 10:18:05 +00:00
OptionArrowButtons ( " Max Threads " , config : : MaxThreads , 1 , 8 ,
2021-03-01 09:13:40 +00:00
" Maximum number of threads to use for texture upscaling. Recommended: number of physical cores minus one " ) ;
2021-03-21 17:00:01 +00:00
# endif
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Load Custom Textures " , config : : CustomTextures ,
" 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 ( ) ;
2021-04-12 20:49:04 +00:00
switch ( renderApi )
{
case 0 :
config : : RendererType = perPixel ? RenderType : : OpenGL_OIT : RenderType : : OpenGL ;
break ;
case 1 :
config : : RendererType = perPixel ? RenderType : : Vulkan_OIT : RenderType : : Vulkan ;
break ;
case 2 :
config : : RendererType = RenderType : : DirectX9 ;
break ;
}
2019-02-06 18:57:13 +00:00
}
if ( ImGui : : BeginTabItem ( " Audio " ) )
{
2019-02-09 20:20:03 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , normal_padding ) ;
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Disable Sound " , config : : DisableSound , " Disable the emulator sound output " ) ;
OptionCheckbox ( " Enable DSP " , config : : DSPEnabled ,
" Enable the Dreamcast Digital Sound Processor. Only recommended on fast platforms " ) ;
2021-03-16 09:15:23 +00:00
# ifdef __ANDROID__
2021-04-30 17:57:11 +00:00
if ( config : : AudioBackend . get ( ) = = " auto " | | config : : AudioBackend . get ( ) = = " android " )
OptionCheckbox ( " Automatic Latency " , config : : AutoLatency ,
" Automatically set audio latency. Recommended " ) ;
2021-03-16 09:15:23 +00:00
# endif
2021-05-01 10:19:04 +00:00
if ( ! config : : AutoLatency
| | ( config : : AudioBackend . get ( ) ! = " auto " & & config : : AudioBackend . get ( ) ! = " android " ) )
2021-03-16 09:15:23 +00:00
{
int latency = ( int ) roundf ( config : : AudioBufferSize * 1000.f / 44100.f ) ;
ImGui : : SliderInt ( " Latency " , & latency , 12 , 512 , " %d ms " ) ;
config : : AudioBufferSize = ( 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 ;
2021-03-01 09:13:40 +00:00
std : : string backend_name = config : : AudioBackend ;
2020-03-14 21:46:40 +00:00
if ( backend_name ! = " auto " )
2019-04-05 20:22:46 +00:00
{
2021-03-01 09:13:40 +00:00
backend = GetAudioBackend ( config : : AudioBackend ) ;
2019-04-05 20:22:46 +00:00
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
{
2021-03-01 09:13:40 +00:00
bool is_selected = ( config : : AudioBackend . get ( ) = = " auto " ) ;
2019-05-20 17:12:28 +00:00
if ( ImGui : : Selectable ( " auto - Automatic driver selection " , & is_selected ) )
2021-03-01 09:13:40 +00:00
config : : AudioBackend . set ( " auto " ) ;
2019-04-05 20:22:46 +00:00
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 ) ;
2021-03-01 09:13:40 +00:00
is_selected = ( config : : AudioBackend . get ( ) = = backend - > slug ) ;
2019-04-05 20:22:46 +00:00
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 ) )
2021-03-01 09:13:40 +00:00
config : : AudioBackend . set ( 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 ) ;
for ( int o = 0 ; o < option_count ; o + + )
{
2021-03-01 09:13:40 +00:00
std : : string value = cfgLoadStr ( current_backend - > slug , options - > cfg_name , " " ) ;
2019-04-24 19:41:38 +00:00
2019-05-02 18:24:49 +00:00
if ( options - > type = = integer )
{
int val = stoi ( value ) ;
2021-03-01 09:13:40 +00:00
if ( ImGui : : SliderInt ( options - > caption . c_str ( ) , & val , options - > min_value , options - > max_value ) )
{
std : : string s = std : : to_string ( val ) ;
cfgSaveStr ( current_backend - > slug , options - > cfg_name , s ) ;
}
2019-05-02 18:24:49 +00:00
}
else if ( options - > type = = checkbox )
{
2021-03-01 09:13:40 +00:00
bool check = value = = " 1 " ;
if ( ImGui : : Checkbox ( options - > caption . c_str ( ) , & check ) )
cfgSaveStr ( current_backend - > slug , options - > cfg_name ,
check ? " 1 " : " 0 " ) ;
2019-05-02 18:24:49 +00:00
}
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 ;
2021-03-01 09:13:40 +00:00
for ( const auto & cur : options - > list_callback ( ) )
2019-04-24 19:41:38 +00:00
{
2021-03-01 09:13:40 +00:00
is_selected = value = = cur ;
2019-04-24 19:41:38 +00:00
if ( ImGui : : Selectable ( cur . c_str ( ) , & is_selected ) )
2021-03-01 09:13:40 +00:00
cfgSaveStr ( current_backend - > slug , options - > cfg_name , cur ) ;
2019-04-24 19:41:38 +00:00
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 ) ;
2021-06-07 10:18:05 +00:00
header ( " CPU Mode " ) ;
2019-02-09 20:20:03 +00:00
{
ImGui : : Columns ( 2 , " cpu_modes " , false ) ;
2021-03-01 09:13:40 +00:00
OptionRadioButton ( " Dynarec " , config : : DynarecEnabled , true ,
" Use the dynamic recompiler. Recommended in most cases " ) ;
2019-02-09 20:20:03 +00:00
ImGui : : NextColumn ( ) ;
2021-03-01 09:13:40 +00:00
OptionRadioButton ( " Interpreter " , config : : DynarecEnabled , false ,
" 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 ) ;
}
2021-06-07 10:18:05 +00:00
if ( config : : DynarecEnabled )
2019-02-09 20:20:03 +00:00
{
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Dynarec Options " ) ;
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Safe Mode " , config : : DynarecSafeMode ,
" Do not optimize integer division. Not recommended " ) ;
OptionCheckbox ( " Idle Skip " , config : : DynarecIdleSkip , " Skip wait loops. Recommended " ) ;
2019-02-09 20:20:03 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Network " ) ;
2020-04-14 15:43:11 +00:00
{
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Broadband Adapter Emulation " , config : : EmulateBBA ,
" Emulate the Ethernet Broadband Adapter (BBA) instead of the Modem " ) ;
OptionCheckbox ( " Enable Naomi Networking " , config : : NetworkEnable ,
" Enable networking for supported Naomi games " ) ;
if ( config : : NetworkEnable )
2020-04-19 19:45:15 +00:00
{
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Act as Server " , config : : ActAsServer ,
" Create a local server for Naomi network games " ) ;
if ( ! config : : ActAsServer )
{
char server_name [ 256 ] ;
strcpy ( server_name , config : : NetworkServer . get ( ) . 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 " ) ;
config : : NetworkServer . set ( server_name ) ;
}
2020-04-19 19:45:15 +00:00
}
2020-04-14 15:43:11 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Other " ) ;
2019-02-09 20:20:03 +00:00
{
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " HLE BIOS " , config : : UseReios , " Force high-level BIOS emulation " ) ;
OptionCheckbox ( " Force Windows CE " , config : : ForceWindowsCE ,
" Enable full MMU emulation and other Windows CE settings. Do not enable unless necessary " ) ;
2019-08-31 20:10:09 +00:00
# ifndef __ANDROID
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Serial Console " , config : : SerialConsole ,
" Dump the Dreamcast serial console to stdout " ) ;
2019-02-09 20:20:03 +00:00
# endif
2021-03-01 09:13:40 +00:00
OptionCheckbox ( " Dump Textures " , config : : DumpTextures ,
" 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 ) ;
2021-06-07 10:18:05 +00:00
header ( " Flycast " ) ;
2019-03-04 23:54:01 +00:00
{
2021-05-28 10:51:04 +00:00
ImGui : : Text ( " Version: %s " , GIT_VERSION ) ;
2019-03-30 11:32:37 +00:00
ImGui : : Text ( " Git Hash: %s " , GIT_HASH ) ;
ImGui : : Text ( " Build Date: %s " , BUILD_DATE ) ;
2019-03-04 23:54:01 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
header ( " Platform " ) ;
2019-03-04 23:54:01 +00:00
{
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 "
2021-03-13 10:37:13 +00:00
# elif defined(__unix__)
2019-03-04 23:54:01 +00:00
" Linux "
2020-04-26 08:03:57 +00:00
# elif defined(__APPLE__)
2019-07-24 16:24:58 +00:00
# ifdef TARGET_IPHONE
2019-03-04 23:54:01 +00:00
" iOS "
# else
2021-05-25 08:11:58 +00:00
" macOS "
2019-03-04 23:54:01 +00:00
# endif
2019-08-25 17:29:56 +00:00
# elif defined(_WIN32)
2019-03-04 23:54:01 +00:00
" Windows "
2021-07-15 14:50:54 +00:00
# elif defined(__SWITCH__)
" Switch "
2019-03-04 23:54:01 +00:00
# else
" Unknown "
# endif
) ;
2021-08-10 15:04:36 +00:00
# ifdef TARGET_IPHONE
extern std : : string iosJitStatus ;
ImGui : : Text ( " JIT Status: %s " , iosJitStatus . c_str ( ) ) ;
# endif
2019-03-04 23:54:01 +00:00
}
2021-06-07 10:18:05 +00:00
ImGui : : Spacing ( ) ;
2021-03-01 09:13:40 +00:00
if ( config : : RendererType . isOpenGL ( ) )
2019-10-15 14:52:02 +00:00
{
2021-06-07 10:18:05 +00:00
header ( " Open GL " ) ;
ImGui : : Text ( " Renderer: %s " , ( const char * ) glGetString ( GL_RENDERER ) ) ;
ImGui : : Text ( " Version: %s " , ( const char * ) glGetString ( GL_VERSION ) ) ;
2019-10-15 14:52:02 +00:00
}
# ifdef USE_VULKAN
2021-04-12 20:49:04 +00:00
else if ( config : : RendererType . isVulkan ( ) )
2019-10-15 14:52:02 +00:00
{
2021-06-07 10:18:05 +00:00
header ( " Vulkan " ) ;
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 ( ) ) ;
2019-10-15 14:52:02 +00:00
}
# endif
2021-04-12 20:49:04 +00:00
# ifdef _WIN32
else if ( config : : RendererType . isDirectX ( ) )
{
if ( ImGui : : CollapsingHeader ( " DirectX " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
std : : string name = theDXContext . getDriverName ( ) ;
ImGui : : Text ( " Driver Name: %s " , name . c_str ( ) ) ;
std : : string version = theDXContext . getDriverVersion ( ) ;
ImGui : : Text ( " Version: %s " , version . c_str ( ) ) ;
}
}
# endif
2019-10-15 14:52:02 +00:00
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 ( ) ;
2020-11-25 12:54:27 +00:00
2021-06-07 10:18:05 +00:00
scrollWhenDraggingOnVoid ( ) ;
windowDragScroll ( ) ;
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
}
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
2021-01-19 10:11:01 +00:00
inline static void gui_display_demo ( )
2019-02-25 16:52:53 +00:00
{
ImGui : : ShowDemoWindow ( ) ;
}
static void gui_display_content ( )
{
2021-06-07 10:18:05 +00:00
fullScreenWindow ( false ) ;
2019-02-25 16:52:53 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0 ) ;
2021-01-03 20:26:56 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowBorderSize , 0 ) ;
2019-02-25 16:52:53 +00:00
ImGui : : Begin ( " ##main " , NULL , ImGuiWindowFlags_NoDecoration ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 20 * scaling , 8 * scaling ) ) ; // from 8, 4
ImGui : : AlignTextToFramePadding ( ) ;
2021-04-06 09:41:04 +00:00
ImGui : : Indent ( 10 * scaling ) ;
2019-02-25 16:52:53 +00:00
ImGui : : Text ( " GAMES " ) ;
2021-04-06 09:41:04 +00:00
ImGui : : Unindent ( 10 * scaling ) ;
2019-02-25 16:52:53 +00:00
static ImGuiTextFilter filter ;
2021-08-06 08:30:30 +00:00
# if !defined(__ANDROID__) && !defined(TARGET_IPHONE)
2021-04-29 16:58:04 +00:00
ImGui : : SameLine ( 0 , 32 * scaling ) ;
filter . Draw ( " Filter " ) ;
# endif
2021-03-01 09:13:40 +00:00
if ( gui_state ! = GuiState : : SelectDisk )
2020-01-30 17:59:26 +00:00
{
2021-04-06 09:41:04 +00:00
ImGui : : SameLine ( ImGui : : GetContentRegionMax ( ) . x - ImGui : : CalcTextSize ( " Settings " ) . x - ImGui : : GetStyle ( ) . FramePadding . x * 2.0f ) ;
if ( ImGui : : Button ( " Settings " ) )
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Settings ;
2020-01-30 17:59:26 +00:00
}
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 " ) )
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : 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 ( ) )
{
2021-03-01 09:13:40 +00:00
if ( gui_state = = GuiState : : 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
{
2021-03-01 09:13:40 +00:00
if ( gui_state = = GuiState : : SelectDisk )
2020-04-09 09:44:19 +00:00
{
strcpy ( settings . imgread . ImagePath , game . path . c_str ( ) ) ;
2021-08-03 08:05:09 +00:00
try {
DiscSwap ( ) ;
gui_state = GuiState : : Closed ;
} catch ( const FlycastException & e ) {
error_msg = e . what ( ) ;
}
2020-04-09 09:44:19 +00:00
}
else
{
2021-03-16 09:15:23 +00:00
std : : string gamePath ( game . path ) ;
2020-04-09 09:44:19 +00:00
scanner . get_mutex ( ) . unlock ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2021-03-05 17:20:55 +00:00
gui_start_game ( gamePath ) ;
2020-04-09 09:44:19 +00:00
scanner . get_mutex ( ) . lock ( ) ;
2021-03-05 17:20:55 +00:00
ImGui : : PopID ( ) ;
break ;
2020-04-09 09:44:19 +00:00
}
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 ( ) ;
}
2021-06-07 10:18:05 +00:00
windowDragScroll ( ) ;
2019-02-25 16:52:53 +00:00
ImGui : : EndChild ( ) ;
ImGui : : End ( ) ;
2021-01-03 20:26:56 +00:00
ImGui : : PopStyleVar ( ) ;
2019-02-25 16:52:53 +00:00
ImGui : : PopStyleVar ( ) ;
2019-03-04 23:54:01 +00:00
error_popup ( ) ;
2020-11-03 21:40:20 +00:00
contentpath_warning_popup ( ) ;
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 )
{
2020-11-26 15:45:57 +00:00
selection + = " / " ;
2019-02-25 16:52:53 +00:00
set_user_config_dir ( selection ) ;
2020-11-26 15:45:57 +00:00
add_system_data_dir ( selection ) ;
2020-12-08 16:15:51 +00:00
std : : string data_path = selection + " data/ " ;
set_user_data_dir ( data_path ) ;
if ( ! file_exists ( data_path ) )
{
if ( ! make_directory ( data_path ) )
{
WARN_LOG ( BOOT , " Cannot create 'data' directory " ) ;
set_user_data_dir ( selection ) ;
}
}
2019-02-25 16:52:53 +00:00
if ( cfgOpen ( ) )
{
2021-03-01 09:13:40 +00:00
config : : Settings : : instance ( ) . load ( false ) ;
2019-11-13 19:08:14 +00:00
// Make sure the renderer type doesn't change mid-flight
2021-03-01 09:13:40 +00:00
config : : RendererType = RenderType : : OpenGL ;
gui_state = GuiState : : Main ;
if ( config : : ContentPath . get ( ) . empty ( ) )
2020-11-25 09:20:03 +00:00
{
scanner . stop ( ) ;
2021-03-01 09:13:40 +00:00
config : : ContentPath . get ( ) . push_back ( selection ) ;
2020-11-25 09:20:03 +00:00
}
2019-03-04 23:54:01 +00:00
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 : : OpenPopup ( " Select System Directory " ) ;
2021-04-06 09:41:04 +00:00
select_file_popup ( " Select System Directory " , & systemdir_selected_callback ) ;
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 ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : NetworkStart ;
2020-04-22 17:11:49 +00:00
}
static void gui_network_start ( )
{
2021-04-06 09:41:04 +00:00
centerNextWindow ( ) ;
2020-04-22 17:11:49 +00:00
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 ( ) )
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2020-04-22 17:11:49 +00:00
ImGui : : Text ( " STARTING... " ) ;
}
else
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Main ;
2020-04-22 17:11:49 +00:00
settings . imgread . ImagePath [ 0 ] = ' \0 ' ;
}
}
else
{
ImGui : : Text ( " STARTING NETWORK... " ) ;
2021-03-01 09:13:40 +00:00
if ( config : : ActAsServer )
2020-04-22 17:11:49 +00:00
ImGui : : Text ( " Press Start to start the game now. " ) ;
}
ImGui : : Text ( " %s " , get_notification ( ) . c_str ( ) ) ;
2020-11-25 12:54:27 +00:00
float currentwidth = ImGui : : GetContentRegionAvail ( ) . x ;
2020-04-22 17:11:49 +00:00
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 ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Main ;
2020-04-22 17:11:49 +00:00
settings . imgread . ImagePath [ 0 ] = ' \0 ' ;
}
ImGui : : PopStyleVar ( ) ;
ImGui : : End ( ) ;
if ( ( kcode [ 0 ] & DC_BTN_START ) = = 0 )
naomiNetwork . startNow ( ) ;
}
static void gui_display_loadscreen ( )
2020-04-20 16:52:02 +00:00
{
2021-04-06 09:41:04 +00:00
centerNextWindow ( ) ;
2020-04-20 16:52:02 +00:00
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
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Closed ;
2020-04-22 17:11:49 +00:00
ImGui : : Text ( " STARTING... " ) ;
}
2021-07-20 17:21:11 +00:00
} catch ( const FlycastException & ex ) {
ERROR_LOG ( BOOT , " %s " , ex . what ( ) ) ;
error_msg = ex . what ( ) ;
2020-04-20 16:52:02 +00:00
# ifdef TEST_AUTOMATION
die ( " Game load failed " ) ;
# endif
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Main ;
2020-04-20 16:52:02 +00:00
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-11-25 12:54:27 +00:00
float currentwidth = ImGui : : GetContentRegionAvail ( ) . x ;
2020-04-20 16:52:02 +00:00
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 ( ) ;
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Main ;
2020-04-20 16:52:02 +00:00
}
}
ImGui : : PopStyleVar ( ) ;
ImGui : : End ( ) ;
}
2019-02-06 18:57:13 +00:00
void gui_display_ui ( )
{
2021-04-06 09:41:04 +00:00
if ( gui_state = = GuiState : : Closed | | gui_state = = GuiState : : VJoyEdit )
return ;
if ( gui_state = = GuiState : : Main )
{
std : : string game_file = settings . imgread . ImagePath ;
if ( ! game_file . empty ( ) )
{
2021-04-20 14:32:49 +00:00
# ifndef __ANDROID__
2021-04-20 13:57:30 +00:00
commandLineStart = true ;
2021-04-20 14:32:49 +00:00
# endif
2021-04-06 09:41:04 +00:00
gui_start_game ( game_file ) ;
return ;
}
}
ImGui_Impl_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
2019-02-06 18:57:13 +00:00
switch ( gui_state )
{
2021-03-01 09:13:40 +00:00
case GuiState : : Settings :
2019-02-06 18:57:13 +00:00
gui_display_settings ( ) ;
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : Commands :
2019-02-06 18:57:13 +00:00
gui_display_commands ( ) ;
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : Main :
2019-02-25 16:52:53 +00:00
//gui_display_demo();
2021-04-06 09:41:04 +00:00
gui_display_content ( ) ;
2019-02-25 16:52:53 +00:00
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : Closed :
2019-02-06 18:57:13 +00:00
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : Onboarding :
2019-02-25 16:52:53 +00:00
gui_display_onboarding ( ) ;
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : VJoyEdit :
2019-03-04 23:54:01 +00:00
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : VJoyEditCommands :
2019-08-25 16:38:36 +00:00
# ifdef __ANDROID__
2021-05-02 09:31:44 +00:00
gui_display_vjoy_commands ( scaling ) ;
2019-03-04 23:54:01 +00:00
# endif
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : SelectDisk :
2020-01-30 17:59:26 +00:00
gui_display_content ( ) ;
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : Loading :
2020-04-20 16:52:02 +00:00
gui_display_loadscreen ( ) ;
break ;
2021-03-01 09:13:40 +00:00
case GuiState : : NetworkStart :
2020-04-22 17:11:49 +00:00
gui_network_start ( ) ;
break ;
2021-04-06 09:41:04 +00:00
case GuiState : : Cheats :
gui_cheats ( ) ;
break ;
2020-04-22 17:11:49 +00:00
default :
die ( " Unknown UI state " ) ;
break ;
2019-02-06 18:57:13 +00:00
}
2021-04-06 09:41:04 +00:00
ImGui : : Render ( ) ;
ImGui_impl_RenderDrawData ( ImGui : : GetDrawData ( ) ) ;
2019-02-06 18:57:13 +00:00
2021-03-01 09:13:40 +00:00
if ( gui_state = = GuiState : : 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 ;
static std : : string getFPSNotification ( )
{
2021-03-01 09:13:40 +00:00
if ( config : : ShowFPS )
2019-02-27 22:02:25 +00:00
{
double now = os_GetSeconds ( ) ;
if ( now - LastFPSTime > = 1.0 ) {
2020-12-15 14:09:42 +00:00
fps = ( MainFrameCount - lastFrameCount ) / ( now - LastFPSTime ) ;
2019-02-27 22:02:25 +00:00
LastFPSTime = now ;
2020-12-15 14:09:42 +00:00
lastFrameCount = MainFrameCount ;
2019-02-27 22:02:25 +00:00
}
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 ] ;
2021-03-19 18:31:01 +00:00
snprintf ( text , sizeof ( text ) , " F:%.1f%s " , fps , settings . input . fastForwardMode ? " >> " : " " ) ;
2019-02-27 22:02:25 +00:00
return std : : string ( text ) ;
}
}
2021-03-19 18:31:01 +00:00
return std : : string ( settings . input . fastForwardMode ? " >> " : " " ) ;
2019-02-27 22:02:25 +00:00
}
void gui_display_osd ( )
{
2021-03-01 09:13:40 +00:00
if ( gui_state = = GuiState : : VJoyEdit )
2019-03-04 23:54:01 +00:00
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 ( ) ;
2021-03-01 09:13:40 +00:00
if ( ! message . empty ( ) | | config : : FloatVMUs | | crosshairsNeeded ( ) )
2019-04-08 13:54:37 +00:00
{
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 ) ;
2021-05-02 09:31:44 +00:00
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , ImGui : : GetIO ( ) . DisplaySize . y ) , ImGuiCond_Always , ImVec2 ( 0.f , 1.f ) ) ; // Lower left corner
ImGui : : SetNextWindowSize ( ImVec2 ( ImGui : : GetIO ( ) . DisplaySize . x , 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 ( ) ;
}
2021-01-23 14:59:57 +00:00
displayCrosshairs ( ) ;
2021-03-01 09:13:40 +00:00
if ( config : : FloatVMUs )
2019-04-08 13:54:37 +00:00
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 ( )
{
2021-03-01 09:13:40 +00:00
gui_state = GuiState : : Onboarding ;
2019-02-25 16:52:53 +00:00
}
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 ( ) ;
2021-03-01 09:13:40 +00:00
if ( config : : RendererType . isOpenGL ( ) )
2019-10-19 16:34:24 +00:00
ImGui_ImplOpenGL3_Shutdown ( ) ;
ImGui : : DestroyContext ( ) ;
2021-01-19 22:52:28 +00:00
EventManager : : unlisten ( Event : : Resume , emuEventCallback ) ;
2019-10-19 16:34:24 +00:00
}
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)
static ImTextureID vmu_lcd_tex_ids [ 8 ] ;
2021-01-23 14:59:57 +00:00
static ImTextureID crosshairTexId ;
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 ;
2021-03-01 09:13:40 +00:00
if ( ! config : : RendererType . isOpenGL ( ) )
2019-10-05 09:50:14 +00:00
return ;
2019-03-29 16:35:00 +00:00
ImGui : : SetNextWindowBgAlpha ( 0 ) ;
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
2021-05-02 09:31:44 +00:00
ImGui : : SetNextWindowSize ( ImGui : : GetIO ( ) . DisplaySize ) ;
2019-03-29 16:35:00 +00:00
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 )
2021-01-23 14:59:57 +00:00
ImGui_ImplOpenGL3_DeleteTexture ( vmu_lcd_tex_ids [ i ] ) ;
2019-03-29 16:35:00 +00:00
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
2021-05-02 09:31:44 +00:00
pos . x = ImGui : : GetIO ( ) . DisplaySize . x - VMU_WIDTH - VMU_PADDING ;
2019-03-29 16:35:00 +00:00
if ( y = = 0 )
{
pos . y = VMU_PADDING ;
if ( i & 1 )
pos . y + = VMU_HEIGHT + VMU_PADDING ;
}
else
{
2021-05-02 09:31:44 +00:00
pos . y = ImGui : : GetIO ( ) . DisplaySize . y - VMU_HEIGHT - VMU_PADDING ;
2019-03-29 16:35:00 +00:00
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 ( ) ;
}
2021-01-23 14:59:57 +00:00
std : : pair < float , float > getCrosshairPosition ( int playerNum )
{
float fx = mo_x_abs [ playerNum ] ;
float fy = mo_y_abs [ playerNum ] ;
2021-03-21 09:32:31 +00:00
float width = 640.f ;
float height = 480.f ;
2021-03-01 09:13:40 +00:00
if ( config : : Rotate90 )
2021-01-23 14:59:57 +00:00
{
float t = fy ;
2021-03-21 09:32:31 +00:00
fy = 639.f - fx ;
2021-01-23 14:59:57 +00:00
fx = t ;
std : : swap ( width , height ) ;
}
2021-03-21 09:32:31 +00:00
float scale = height / screen_height ;
fy / = scale ;
scale / = config : : ScreenStretching / 100.f ;
fx = fx / scale + ( screen_width - width / scale ) / 2.f ;
2021-01-23 14:59:57 +00:00
return std : : make_pair ( fx , fy ) ;
}
static void displayCrosshairs ( )
{
if ( ! game_started )
return ;
2021-03-01 09:13:40 +00:00
if ( ! config : : RendererType . isOpenGL ( ) )
2021-01-23 14:59:57 +00:00
return ;
if ( ! crosshairsNeeded ( ) )
return ;
if ( crosshairTexId = = ImTextureID ( ) )
crosshairTexId = ImGui_ImplOpenGL3_CreateCrosshairTexture ( getCrosshairTextureData ( ) ) ;
ImGui : : SetNextWindowBgAlpha ( 0 ) ;
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
2021-05-02 09:31:44 +00:00
ImGui : : SetNextWindowSize ( ImGui : : GetIO ( ) . DisplaySize ) ;
2021-01-23 14:59:57 +00:00
ImGui : : Begin ( " xhair-window " , NULL , ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs
| ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoFocusOnAppearing ) ;
2021-03-01 09:13:40 +00:00
for ( u32 i = 0 ; i < config : : CrosshairColor . size ( ) ; i + + )
2021-01-23 14:59:57 +00:00
{
2021-03-01 09:13:40 +00:00
if ( config : : CrosshairColor [ i ] = = 0 )
2021-01-23 14:59:57 +00:00
continue ;
2021-03-01 09:13:40 +00:00
if ( settings . platform . system = = DC_PLATFORM_DREAMCAST & & config : : MapleMainDevices [ i ] ! = MDT_LightGun )
2021-01-23 14:59:57 +00:00
continue ;
ImVec2 pos ;
std : : tie ( pos . x , pos . y ) = getCrosshairPosition ( i ) ;
2021-07-08 10:47:00 +00:00
pos . x - = ( XHAIR_WIDTH * scaling ) / 2.f ;
pos . y + = ( XHAIR_WIDTH * scaling ) / 2.f ;
ImVec2 pos_b ( pos . x + XHAIR_WIDTH * scaling , pos . y - XHAIR_HEIGHT * scaling ) ;
2021-01-23 14:59:57 +00:00
2021-03-01 09:13:40 +00:00
ImGui : : GetWindowDrawList ( ) - > AddImage ( crosshairTexId , pos , pos_b , ImVec2 ( 0 , 1 ) , ImVec2 ( 1 , 0 ) , config : : CrosshairColor [ i ] ) ;
2021-01-23 14:59:57 +00:00
}
ImGui : : End ( ) ;
}
2019-03-29 16:35:00 +00:00
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 ( )
{
2021-03-01 09:13:40 +00:00
if ( ! config : : RendererType . isOpenGL ( ) )
2019-10-05 09:50:14 +00:00
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
{
2021-01-23 14:59:57 +00:00
if ( vmu_lcd_tex_ids [ i ] ! = ImTextureID ( ) )
2019-03-29 16:35:00 +00:00
{
2021-01-23 14:59:57 +00:00
ImGui_ImplOpenGL3_DeleteTexture ( vmu_lcd_tex_ids [ i ] ) ;
vmu_lcd_tex_ids [ i ] = ImTextureID ( ) ;
2019-03-29 16:35:00 +00:00
}
}
2021-01-23 14:59:57 +00:00
if ( crosshairTexId ! = ImTextureID ( ) )
{
ImGui_ImplOpenGL3_DeleteTexture ( crosshairTexId ) ;
crosshairTexId = ImTextureID ( ) ;
}
2019-03-29 16:35:00 +00:00
}