2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
2012-11-04 23:01:49 +01:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2017-02-24 20:50:27 +01:00
# include "ppsspp_config.h"
2014-12-21 18:50:07 -08:00
# include <algorithm>
2021-07-08 21:30:23 +02:00
# include <functional>
using namespace std : : placeholders ;
2015-02-01 18:04:06 +01:00
2020-10-04 23:24:14 +02:00
# include "Common/Render/TextureAtlas.h"
# include "Common/GPU/OpenGL/GLFeatures.h"
2020-10-05 00:05:28 +02:00
# include "Common/Render/Text/draw_text.h"
2024-02-02 09:02:40 +01:00
# include "Common/File/FileUtil.h"
2023-01-27 11:19:29 +03:00
# include "Common/Battery/Battery.h"
2012-11-01 16:19:01 +01:00
2020-10-04 20:48:47 +02:00
# include "Common/UI/Root.h"
# include "Common/UI/UI.h"
# include "Common/UI/Context.h"
# include "Common/UI/Tween.h"
# include "Common/UI/View.h"
2022-11-21 20:15:22 +01:00
# include "Common/UI/AsyncImageFileView.h"
2022-11-17 12:19:17 +01:00
# include "Common/VR/PPSSPPVR.h"
2012-11-01 16:19:01 +01:00
2020-10-01 13:05:04 +02:00
# include "Common/Data/Text/I18n.h"
# include "Common/Input/InputState.h"
2020-08-15 15:22:44 +02:00
# include "Common/Log.h"
2020-10-04 10:30:18 +02:00
# include "Common/System/Display.h"
# include "Common/System/System.h"
# include "Common/System/NativeApp.h"
2023-03-22 22:17:53 +01:00
# include "Common/System/Request.h"
2023-06-30 17:15:49 +02:00
# include "Common/System/OSD.h"
2020-10-04 10:30:18 +02:00
# include "Common/Profiler/Profiler.h"
# include "Common/Math/curves.h"
2020-08-15 20:53:08 +02:00
# include "Common/TimeUtil.h"
2013-06-30 21:43:01 -07:00
2016-09-01 20:09:56 -04:00
# ifndef MOBILE_DEVICE
2016-08-27 14:38:05 -04:00
# include "Core/AVIDump.h"
2016-09-01 20:09:56 -04:00
# endif
2013-03-29 20:51:14 +01:00
# include "Core/Config.h"
2018-06-16 18:42:31 -07:00
# include "Core/ConfigValues.h"
2013-03-29 20:51:14 +01:00
# include "Core/CoreTiming.h"
# include "Core/CoreParameter.h"
# include "Core/Core.h"
2020-10-04 00:25:21 +02:00
# include "Core/KeyMap.h"
2020-12-19 20:26:02 +01:00
# include "Core/MemFault.h"
2014-02-09 14:04:16 -08:00
# include "Core/Reporting.h"
2013-03-29 20:51:14 +01:00
# include "Core/System.h"
2024-02-02 09:02:40 +01:00
# include "Core/FileSystems/VirtualDiscFileSystem.h"
2013-03-29 20:51:14 +01:00
# include "GPU/GPUState.h"
# include "GPU/GPUInterface.h"
2020-08-03 23:17:22 +02:00
# include "GPU/Common/FramebufferManagerCommon.h"
2018-02-05 16:21:39 +01:00
# if !PPSSPP_PLATFORM(UWP)
2018-01-17 13:59:32 +01:00
# include "GPU/Vulkan/DebugVisVulkan.h"
2018-02-05 16:21:39 +01:00
# endif
2024-07-25 10:08:56 +02:00
# include "Core/MIPS/MIPS.h"
2013-03-29 20:51:14 +01:00
# include "Core/HLE/sceCtrl.h"
2015-10-28 21:20:20 +01:00
# include "Core/HLE/sceSas.h"
2013-03-29 20:51:14 +01:00
# include "Core/Debugger/SymbolMap.h"
2023-07-02 12:00:13 +02:00
# include "Core/RetroAchievements.h"
2013-10-30 22:46:27 +05:30
# include "Core/SaveState.h"
2024-11-04 01:05:36 +01:00
# include "UI/ImDebugger/ImDebugger.h"
2015-01-29 12:55:49 +01:00
# include "Core/HLE/__sceAudio.h"
2024-11-04 01:05:36 +01:00
// #include "Core/HLE/proAdhoc.h"
2022-01-30 09:41:08 -08:00
# include "Core/HW/Display.h"
2012-11-01 16:19:01 +01:00
2016-09-04 08:42:20 -07:00
# include "UI/BackgroundAudio.h"
2013-12-05 14:14:15 +01:00
# include "UI/OnScreenDisplay.h"
2013-04-07 22:43:23 +02:00
# include "UI/GamepadEmu.h"
2014-12-22 10:48:17 +01:00
# include "UI/PauseScreen.h"
2013-06-10 22:06:51 +02:00
# include "UI/MainScreen.h"
2013-04-07 22:43:23 +02:00
# include "UI/EmuScreen.h"
2013-09-07 20:54:11 +02:00
# include "UI/DevScreens.h"
2013-04-13 21:24:07 +02:00
# include "UI/GameInfoCache.h"
2013-07-15 17:41:24 +02:00
# include "UI/MiscScreens.h"
2013-09-07 11:29:44 -04:00
# include "UI/ControlMappingScreen.h"
2015-12-21 06:32:05 +01:00
# include "UI/DisplayLayoutScreen.h"
2013-09-07 11:29:44 -04:00
# include "UI/GameSettingsScreen.h"
2015-10-14 17:45:21 +02:00
# include "UI/ProfilerDraw.h"
2018-08-13 00:08:56 +02:00
# include "UI/DiscordIntegration.h"
2016-10-21 18:35:54 +08:00
# include "UI/ChatScreen.h"
2023-08-02 14:28:52 +02:00
# include "UI/DebugOverlay.h"
2013-07-17 02:33:26 -03:00
2024-10-30 08:07:59 +01:00
# include "ext/imgui/imgui.h"
# include "ext/imgui/imgui_impl_thin3d.h"
2024-10-30 23:59:57 +01:00
# include "ext/imgui/imgui_impl_platform.h"
2024-10-30 08:07:59 +01:00
2023-01-25 00:43:17 +01:00
# include "Core/Reporting.h"
2020-03-08 14:32:32 +01:00
# if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
2016-03-20 20:26:52 +01:00
# include "Windows/MainWindow.h"
# endif
2016-09-01 20:09:56 -04:00
# ifndef MOBILE_DEVICE
2017-11-14 06:33:49 +01:00
static AVIDump avi ;
2016-09-01 20:09:56 -04:00
# endif
2016-08-27 14:38:05 -04:00
2021-07-08 21:30:23 +02:00
// TODO: Ugly!
2016-08-30 09:09:38 -04:00
static bool frameStep_ ;
static int lastNumFlips ;
2016-08-27 14:38:05 -04:00
static bool startDumping ;
2016-08-28 00:20:03 -04:00
2019-04-30 19:01:20 -07:00
extern bool g_TakeScreenshot ;
2016-08-28 00:20:03 -04:00
static void __EmuScreenVblank ( )
{
2023-04-06 00:34:50 +02:00
auto sy = GetI18NCategory ( I18NCat : : SYSTEM ) ;
2017-06-03 08:37:55 -07:00
2016-08-29 15:34:00 -04:00
if ( frameStep_ & & lastNumFlips ! = gpuStats . numFlips )
2016-08-28 00:20:03 -04:00
{
frameStep_ = false ;
2024-11-01 22:52:47 +01:00
Core_Break ( " ui.frameAdvance " , 0 ) ;
2016-08-29 15:34:00 -04:00
lastNumFlips = gpuStats . numFlips ;
2016-08-28 00:20:03 -04:00
}
2016-09-01 20:09:56 -04:00
# ifndef MOBILE_DEVICE
2016-08-27 14:38:05 -04:00
if ( g_Config . bDumpFrames & & ! startDumping )
{
avi . Start ( PSP_CoreParameter ( ) . renderWidth , PSP_CoreParameter ( ) . renderHeight ) ;
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sy - > T ( " AVI Dump started. " ) , 1.0f ) ;
2016-08-27 14:38:05 -04:00
startDumping = true ;
}
if ( g_Config . bDumpFrames & & startDumping )
{
avi . AddFrame ( ) ;
}
else if ( ! g_Config . bDumpFrames & & startDumping )
{
avi . Stop ( ) ;
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sy - > T ( " AVI Dump stopped. " ) , 1.0f ) ;
2016-08-27 14:38:05 -04:00
startDumping = false ;
}
2016-09-01 20:09:56 -04:00
# endif
2016-08-28 00:20:03 -04:00
}
2021-07-08 21:30:23 +02:00
// Handles control rotation due to internal screen rotation.
2021-07-09 11:01:56 +02:00
static void SetPSPAnalog ( int stick , float x , float y ) {
2021-07-09 10:52:48 +02:00
switch ( g_Config . iInternalScreenRotation ) {
case ROTATION_LOCKED_HORIZONTAL :
// Standard rotation. No change.
break ;
case ROTATION_LOCKED_HORIZONTAL180 :
x = - x ;
y = - y ;
break ;
case ROTATION_LOCKED_VERTICAL :
{
float new_y = - x ;
x = y ;
y = new_y ;
break ;
}
case ROTATION_LOCKED_VERTICAL180 :
{
float new_y = y = x ;
x = - y ;
y = new_y ;
break ;
}
default :
break ;
}
2021-07-09 10:41:26 +02:00
__CtrlSetAnalogXY ( stick , x , y ) ;
2021-07-08 21:30:23 +02:00
}
2021-05-06 01:31:38 +02:00
EmuScreen : : EmuScreen ( const Path & filename )
2021-07-08 21:30:23 +02:00
: gamePath_ ( filename ) {
2016-05-27 20:41:37 -07:00
saveStateSlot_ = SaveState : : GetCurrentSlot ( ) ;
2016-08-28 00:20:03 -04:00
__DisplayListenVblank ( __EmuScreenVblank ) ;
2016-08-28 18:18:44 -04:00
frameStep_ = false ;
2016-08-29 15:34:00 -04:00
lastNumFlips = gpuStats . numFlips ;
2016-08-27 14:38:05 -04:00
startDumping = false ;
2021-07-08 21:30:23 +02:00
controlMapper_ . SetCallbacks (
2023-03-30 10:47:28 +02:00
std : : bind ( & EmuScreen : : onVKey , this , _1 , _2 ) ,
2023-03-30 15:03:41 +02:00
std : : bind ( & EmuScreen : : onVKeyAnalog , this , _1 , _2 ) ,
2023-03-30 10:47:28 +02:00
[ ] ( uint32_t bitsToSet , uint32_t bitsToClear ) {
2023-04-01 08:55:45 +02:00
__CtrlUpdateButtons ( bitsToSet , bitsToClear ) ;
2023-03-30 10:47:28 +02:00
} ,
2023-03-31 11:11:46 +02:00
& SetPSPAnalog ,
nullptr ) ;
2020-07-04 20:57:05 +02:00
2018-09-17 22:45:09 -07:00
// Make sure we don't leave it at powerdown after the last game.
2020-07-04 20:57:05 +02:00
// TODO: This really should be handled elsewhere if it isn't.
2018-09-17 22:45:09 -07:00
if ( coreState = = CORE_POWERDOWN )
coreState = CORE_STEPPING ;
2017-04-17 20:33:22 -07:00
OnDevMenu . Handle ( this , & EmuScreen : : OnDevTools ) ;
2017-07-08 18:08:33 +08:00
OnChatMenu . Handle ( this , & EmuScreen : : OnChat ) ;
2021-10-08 09:23:22 -07:00
// Usually, we don't want focus movement enabled on this screen, so disable on start.
// Only if you open chat or dev tools do we want it to start working.
UI : : EnableFocusMovement ( false ) ;
2024-10-30 08:07:59 +01:00
// TODO: Do this only on demand.
IMGUI_CHECKVERSION ( ) ;
ImGui : : CreateContext ( ) ;
2013-07-17 02:33:26 -03:00
}
2021-05-06 01:31:38 +02:00
bool EmuScreen : : bootAllowStorage ( const Path & filename ) {
2018-04-01 23:28:36 -07:00
// No permissions needed. The easy life.
2021-05-06 01:31:38 +02:00
if ( filename . Type ( ) = = PathType : : HTTP )
2018-04-01 23:28:36 -07:00
return true ;
2021-05-06 01:31:38 +02:00
2018-04-01 23:28:36 -07:00
if ( ! System_GetPropertyBool ( SYSPROP_SUPPORTS_PERMISSIONS ) )
return true ;
PermissionStatus status = System_GetPermissionStatus ( SYSTEM_PERMISSION_STORAGE ) ;
switch ( status ) {
case PERMISSION_STATUS_UNKNOWN :
System_AskForPermission ( SYSTEM_PERMISSION_STORAGE ) ;
return false ;
case PERMISSION_STATUS_DENIED :
stopRender_ = true ;
screenManager ( ) - > switchScreen ( new MainScreen ( ) ) ;
return false ;
case PERMISSION_STATUS_PENDING :
// Keep waiting.
return false ;
case PERMISSION_STATUS_GRANTED :
return true ;
}
2018-04-08 23:54:46 -07:00
_assert_ ( false ) ;
return false ;
2018-04-01 23:28:36 -07:00
}
2021-05-06 01:31:38 +02:00
void EmuScreen : : bootGame ( const Path & filename ) {
2023-07-24 12:08:15 +02:00
if ( Achievements : : IsBlockingExecution ( ) ) {
// Keep waiting.
return ;
}
2022-10-02 07:25:15 -07:00
if ( PSP_IsRebooting ( ) )
return ;
if ( PSP_IsInited ( ) ) {
bootPending_ = false ;
invalid_ = false ;
bootComplete ( ) ;
return ;
}
2014-01-19 14:17:34 -08:00
if ( PSP_IsIniting ( ) ) {
2023-07-24 12:00:16 +02:00
std : : string error_string = " (unknown error) " ;
2023-07-24 12:08:15 +02:00
2014-05-15 22:17:19 -07:00
bootPending_ = ! PSP_InitUpdate ( & error_string ) ;
2023-07-12 01:11:09 +02:00
2014-05-15 22:17:19 -07:00
if ( ! bootPending_ ) {
2014-01-19 14:17:34 -08:00
invalid_ = ! PSP_IsInited ( ) ;
if ( invalid_ ) {
errorMessage_ = error_string ;
2024-07-14 14:42:59 +02:00
ERROR_LOG ( Log : : Boot , " isIniting bootGame error: %s " , errorMessage_ . c_str ( ) ) ;
2014-01-19 14:17:34 -08:00
return ;
}
bootComplete ( ) ;
}
return ;
}
2021-05-06 01:31:38 +02:00
g_BackgroundAudio . SetGame ( Path ( ) ) ;
2016-09-04 08:42:20 -07:00
2018-04-01 23:28:36 -07:00
// Check permission status first, in case we came from a shortcut.
if ( ! bootAllowStorage ( filename ) )
return ;
2018-08-22 18:27:20 -07:00
invalid_ = true ;
// We don't want to boot with the wrong game specific config, so wait until info is ready.
2024-01-28 16:23:27 +01:00
std : : shared_ptr < GameInfo > info = g_gameInfoCache - > GetInfo ( nullptr , filename , GameInfoFlags : : PARAM_SFO ) ;
2024-01-28 16:56:07 +01:00
if ( ! info - > Ready ( GameInfoFlags : : PARAM_SFO ) ) {
2018-08-22 18:27:20 -07:00
return ;
2024-01-28 16:56:07 +01:00
}
2018-08-22 18:27:20 -07:00
2024-01-20 23:01:08 +01:00
auto sc = GetI18NCategory ( I18NCat : : SCREEN ) ;
if ( info - > fileType = = IdentifiedFileType : : PSP_DISC_DIRECTORY ) {
2024-02-02 09:02:40 +01:00
// Check for existence of ppsspp-index.lst - if it exists, the user likely knows what they're doing.
// TODO: Better would be to check that it was loaded successfully.
if ( ! File : : Exists ( filename / INDEX_FILENAME ) ) {
g_OSD . Show ( OSDType : : MESSAGE_CENTERED_WARNING , sc - > T ( " ExtractedIsoWarning " , " Extracted ISOs often don't work. \n Play the ISO file directly. " ) , gamePath_ . ToVisualString ( ) , 7.0f ) ;
} else {
2024-07-14 14:42:59 +02:00
INFO_LOG ( Log : : Loader , " Extracted ISO loaded without warning - %s is present. " , INDEX_FILENAME . c_str ( ) ) ;
2024-02-02 09:02:40 +01:00
}
2024-01-20 23:01:08 +01:00
}
2024-01-18 23:00:43 +01:00
extraAssertInfoStr_ = info - > id + " " + info - > GetTitle ( ) ;
SetExtraAssertInfo ( extraAssertInfoStr_ . c_str ( ) ) ;
2022-12-16 14:55:56 +01:00
2018-08-22 18:27:20 -07:00
if ( ! info - > id . empty ( ) ) {
2019-07-17 21:28:21 -07:00
g_Config . loadGameConfig ( info - > id , info - > GetTitle ( ) ) ;
2017-12-09 14:11:39 -08:00
// Reset views in case controls are in a different place.
RecreateViews ( ) ;
2018-08-13 00:08:56 +02:00
2024-01-19 13:44:49 +01:00
g_Discord . SetPresenceGame ( info - > GetTitle ( ) ) ;
2018-08-13 00:08:56 +02:00
} else {
2018-08-13 20:14:34 +02:00
g_Discord . SetPresenceGame ( sc - > T ( " Untitled PSP game " ) ) ;
2014-12-14 20:33:20 +01:00
}
2017-03-06 13:50:22 +01:00
CoreParameter coreParam { } ;
2016-05-08 01:43:27 +02:00
coreParam . cpuCore = ( CPUCore ) g_Config . iCpuCore ;
2016-04-10 10:21:48 +02:00
coreParam . gpuCore = GPUCORE_GLES ;
2015-10-10 16:41:19 +02:00
switch ( GetGPUBackend ( ) ) {
2017-02-24 20:50:27 +01:00
case GPUBackend : : DIRECT3D11 :
coreParam . gpuCore = GPUCORE_DIRECTX11 ;
break ;
# if !PPSSPP_PLATFORM(UWP)
2019-05-10 23:25:57 +02:00
# if PPSSPP_API(ANY_GL)
2015-10-10 16:41:19 +02:00
case GPUBackend : : OPENGL :
2016-04-10 10:21:48 +02:00
coreParam . gpuCore = GPUCORE_GLES ;
2015-10-10 16:41:19 +02:00
break ;
2019-05-04 06:06:50 +08:00
# endif
2015-10-10 16:41:19 +02:00
case GPUBackend : : DIRECT3D9 :
2016-04-10 10:21:48 +02:00
coreParam . gpuCore = GPUCORE_DIRECTX9 ;
2015-10-10 16:41:19 +02:00
break ;
case GPUBackend : : VULKAN :
2016-04-10 10:21:48 +02:00
coreParam . gpuCore = GPUCORE_VULKAN ;
2015-10-10 16:41:19 +02:00
break ;
2017-02-24 20:50:27 +01:00
# endif
2014-08-17 21:29:36 +02:00
}
2018-11-21 22:15:01 +01:00
2016-01-03 11:05:36 -08:00
// Preserve the existing graphics context.
coreParam . graphicsContext = PSP_CoreParameter ( ) . graphicsContext ;
2012-11-01 16:19:01 +01:00
coreParam . enableSound = g_Config . bEnableSound ;
2014-01-19 14:17:34 -08:00
coreParam . fileToStart = filename ;
2021-05-09 17:24:04 -07:00
coreParam . mountIso . clear ( ) ;
coreParam . mountRoot . clear ( ) ;
2018-06-23 10:14:36 -07:00
coreParam . startBreak = ! g_Config . bAutoRun ;
2012-11-01 16:19:01 +01:00
coreParam . headLess = false ;
2013-09-11 00:19:34 +02:00
if ( g_Config . iInternalResolution = = 0 ) {
2023-02-25 13:09:44 +01:00
coreParam . renderWidth = g_display . pixel_xres ;
coreParam . renderHeight = g_display . pixel_yres ;
2013-09-11 00:19:34 +02:00
} else {
if ( g_Config . iInternalResolution < 0 )
g_Config . iInternalResolution = 1 ;
coreParam . renderWidth = 480 * g_Config . iInternalResolution ;
coreParam . renderHeight = 272 * g_Config . iInternalResolution ;
}
2023-02-25 13:09:44 +01:00
coreParam . pixelWidth = g_display . pixel_xres ;
coreParam . pixelHeight = g_display . pixel_yres ;
2013-09-11 00:19:34 +02:00
2012-11-01 16:19:01 +01:00
std : : string error_string ;
2014-01-19 14:17:34 -08:00
if ( ! PSP_InitStart ( coreParam , & error_string ) ) {
2014-05-15 22:17:19 -07:00
bootPending_ = false ;
2012-11-01 16:19:01 +01:00
invalid_ = true ;
errorMessage_ = error_string ;
2024-07-14 14:42:59 +02:00
ERROR_LOG ( Log : : Boot , " InitStart bootGame error: %s " , errorMessage_ . c_str ( ) ) ;
2012-11-01 16:19:01 +01:00
}
2017-03-14 10:36:51 +01:00
2024-10-22 20:58:40 +02:00
if ( PSP_CoreParameter ( ) . compat . flags ( ) . RequireBufferedRendering & & g_Config . bSkipBufferEffects & & ! g_Config . bSoftwareRendering ) {
2023-04-06 00:34:50 +02:00
auto gr = GetI18NCategory ( I18NCat : : GRAPHICS ) ;
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , gr - > T ( " BufferedRenderingRequired " , " Warning: This game requires Rendering Mode to be set to Buffered. " ) , 10.0f ) ;
2017-03-14 10:36:51 +01:00
}
2017-03-21 14:23:31 +07:00
2024-07-20 11:23:34 +02:00
if ( PSP_CoreParameter ( ) . compat . flags ( ) . RequireBlockTransfer & & g_Config . iSkipGPUReadbackMode ! = ( int ) SkipGPUReadbackMode : : NO_SKIP & & ! PSP_CoreParameter ( ) . compat . flags ( ) . ForceEnableGPUReadback ) {
2023-04-06 00:34:50 +02:00
auto gr = GetI18NCategory ( I18NCat : : GRAPHICS ) ;
2023-12-13 14:10:30 +01:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , gr - > T ( " BlockTransferRequired " , " Warning: This game requires Skip GPU Readbacks be set to No. " ) , 10.0f ) ;
2017-03-21 14:23:31 +07:00
}
2017-12-03 11:56:42 -08:00
2017-12-17 13:14:06 +01:00
if ( PSP_CoreParameter ( ) . compat . flags ( ) . RequireDefaultCPUClock & & g_Config . iLockedCPUSpeed ! = 0 ) {
2023-04-06 00:34:50 +02:00
auto gr = GetI18NCategory ( I18NCat : : GRAPHICS ) ;
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , gr - > T ( " DefaultCPUClockRequired " , " Warning: This game requires the CPU clock to be set to default. " ) , 10.0f ) ;
2017-12-17 13:14:06 +01:00
}
2018-01-01 23:07:48 -08:00
loadingViewColor_ - > Divert ( 0xFFFFFFFF , 0.75f ) ;
loadingViewVisible_ - > Divert ( UI : : V_VISIBLE , 0.75f ) ;
2022-10-10 10:53:27 +02:00
screenManager ( ) - > getDrawContext ( ) - > ResetStats ( ) ;
2023-12-10 21:57:05 +01:00
if ( bootPending_ ) {
System_PostUIMessage ( UIMessage : : GAME_SELECTED , filename . c_str ( ) ) ;
}
2014-01-19 14:17:34 -08:00
}
2013-05-16 17:18:29 +02:00
2014-01-19 14:17:34 -08:00
void EmuScreen : : bootComplete ( ) {
2014-06-22 09:38:46 +02:00
UpdateUIState ( UISTATE_INGAME ) ;
2023-03-21 11:10:09 +01:00
System_Notify ( SystemNotification : : BOOT_DONE ) ;
2023-03-21 11:21:19 +01:00
System_Notify ( SystemNotification : : DISASSEMBLY ) ;
2013-03-29 20:51:14 +01:00
2024-07-14 14:42:59 +02:00
NOTICE_LOG ( Log : : Boot , " Booted %s... " , PSP_CoreParameter ( ) . fileToStart . c_str ( ) ) ;
2023-12-03 16:41:29 +01:00
if ( ! Achievements : : HardcoreModeActive ( ) ) {
2023-11-30 17:33:14 +01:00
// Don't auto-load savestates in hardcore mode.
2023-07-12 01:11:09 +02:00
autoLoad ( ) ;
}
2013-10-30 23:21:25 +05:30
2023-04-06 00:34:50 +02:00
auto sc = GetI18NCategory ( I18NCat : : SCREEN ) ;
2013-06-11 00:51:10 +02:00
2014-02-08 11:11:50 -08:00
# ifndef MOBILE_DEVICE
2013-06-11 00:51:10 +02:00
if ( g_Config . bFirstRun ) {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " PressESC " , " Press ESC to open the pause menu " ) ) ;
2013-06-11 00:51:10 +02:00
}
# endif
2013-09-17 10:27:42 +02:00
2017-02-24 20:50:27 +01:00
# if !PPSSPP_PLATFORM(UWP)
2016-01-05 22:37:28 -08:00
if ( GetGPUBackend ( ) = = GPUBackend : : OPENGL ) {
2018-01-16 14:16:56 +01:00
const char * renderer = gl_extensions . model ;
2014-08-17 21:29:36 +02:00
if ( strstr ( renderer , " Chainfire3D " ) ! = 0 ) {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , sc - > T ( " Chainfire3DWarning " , " WARNING: Chainfire3D detected, may cause problems " ) , 10.0f ) ;
2014-08-17 21:29:36 +02:00
} else if ( strstr ( renderer , " GLTools " ) ! = 0 ) {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , sc - > T ( " GLToolsWarning " , " WARNING: GLTools detected, may cause problems " ) , 10.0f ) ;
2014-08-17 21:29:36 +02:00
}
2015-10-11 11:46:24 +02:00
if ( g_Config . bGfxDebugOutput ) {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , " WARNING: GfxDebugOutput is enabled via ppsspp.ini. Things may be slow. " , 10.0f ) ;
2015-10-11 11:46:24 +02:00
}
2013-09-17 10:27:42 +02:00
}
2017-02-24 20:50:27 +01:00
# endif
2013-10-30 22:46:27 +05:30
2016-07-24 17:04:06 -07:00
if ( Core_GetPowerSaving ( ) ) {
2023-04-06 00:34:50 +02:00
auto sy = GetI18NCategory ( I18NCat : : SYSTEM ) ;
2016-10-12 11:13:16 +02:00
# ifdef __ANDROID__
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , sy - > T ( " WARNING: Android battery save mode is on " ) , 2.0f , " core_powerSaving " ) ;
2016-10-10 17:32:25 -07:00
# else
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , sy - > T ( " WARNING: Battery save mode is on " ) , 2.0f , " core_powerSaving " ) ;
2016-10-10 17:32:25 -07:00
# endif
2016-07-24 17:04:06 -07:00
}
2023-12-18 13:11:39 +01:00
if ( g_Config . bStereoRendering ) {
auto gr = GetI18NCategory ( I18NCat : : GRAPHICS ) ;
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
// Stereo rendering is experimental, so let's notify the user it's being used.
// Carefully reuse translations for this rare warning.
2024-01-19 13:44:49 +01:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , std : : string ( gr - > T ( " Stereo rendering " ) ) + " : " + std : : string ( di - > T ( " Enabled " ) ) ) ;
2023-12-18 13:11:39 +01:00
}
2016-08-16 21:24:01 -07:00
saveStateSlot_ = SaveState : : GetCurrentSlot ( ) ;
2017-12-03 11:56:42 -08:00
loadingViewColor_ - > Divert ( 0x00FFFFFF , 0.2f ) ;
loadingViewVisible_ - > Divert ( UI : : V_INVISIBLE , 0.2f ) ;
2023-11-20 11:46:36 +01:00
std : : string gameID = g_paramSFO . GetValueString ( " DISC_ID " ) ;
g_Config . TimeTracker ( ) . Start ( gameID ) ;
2012-11-01 16:19:01 +01:00
}
2013-03-29 21:21:27 +01:00
EmuScreen : : ~ EmuScreen ( ) {
2024-11-05 11:18:26 +01:00
if ( imguiInited_ ) {
ImGui_ImplThin3d_Shutdown ( ) ;
ImGui : : DestroyContext ( ) ;
}
2024-10-30 08:07:59 +01:00
2023-11-20 11:46:36 +01:00
std : : string gameID = g_paramSFO . GetValueString ( " DISC_ID " ) ;
g_Config . TimeTracker ( ) . Stop ( gameID ) ;
2023-07-10 21:04:22 +02:00
// If we were invalid, it would already be shutdown.
2018-11-01 21:27:01 -07:00
if ( ! invalid_ | | bootPending_ ) {
2012-11-01 16:19:01 +01:00
PSP_Shutdown ( ) ;
}
2023-11-20 11:46:36 +01:00
2023-12-10 21:57:05 +01:00
System_PostUIMessage ( UIMessage : : GAME_SELECTED , " " ) ;
2023-07-10 21:04:22 +02:00
g_OSD . ClearAchievementStuff ( ) ;
2022-12-17 22:17:29 +01:00
SetExtraAssertInfo ( nullptr ) ;
2016-09-01 20:09:56 -04:00
# ifndef MOBILE_DEVICE
2016-08-27 14:38:05 -04:00
if ( g_Config . bDumpFrames & & startDumping )
{
avi . Stop ( ) ;
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , " AVI Dump stopped. " , 2.0f ) ;
2016-08-27 14:38:05 -04:00
startDumping = false ;
}
2016-09-01 20:09:56 -04:00
# endif
2018-11-10 07:48:04 -08:00
if ( GetUIState ( ) = = UISTATE_EXIT )
g_Discord . ClearPresence ( ) ;
else
g_Discord . SetPresenceMenu ( ) ;
2012-11-01 16:19:01 +01:00
}
void EmuScreen : : dialogFinished ( const Screen * dialog , DialogResult result ) {
2024-10-02 00:59:57 +02:00
if ( std : : string_view ( dialog - > tag ( ) ) = = " TextEditPopup " ) {
// Chat message finished.
return ;
}
2013-07-17 02:33:26 -03:00
// TODO: improve the way with which we got commands from PauseMenu.
2013-10-25 13:19:08 +02:00
// DR_CANCEL/DR_BACK means clicked on "continue", DR_OK means clicked on "back to menu",
2023-07-06 17:18:46 +02:00
// DR_YES means a message sent to PauseMenu by System_PostUIMessage.
2014-01-25 00:40:14 -08:00
if ( result = = DR_OK | | quit_ ) {
2013-08-18 20:14:33 +02:00
screenManager ( ) - > switchScreen ( new MainScreen ( ) ) ;
2014-01-25 00:40:14 -08:00
quit_ = false ;
2012-11-01 16:19:01 +01:00
}
2022-05-29 11:16:15 -07:00
// Returning to the PauseScreen, unless we're stepping, means we should go back to controls.
if ( Core_IsActive ( ) )
UI : : EnableFocusMovement ( false ) ;
2013-07-20 12:06:06 +02:00
RecreateViews ( ) ;
2024-01-18 23:00:43 +01:00
SetExtraAssertInfo ( extraAssertInfoStr_ . c_str ( ) ) ;
2012-11-01 16:19:01 +01:00
}
2024-01-19 13:44:49 +01:00
static void AfterSaveStateAction ( SaveState : : Status status , std : : string_view message , void * ) {
2019-06-03 12:21:22 +02:00
if ( ! message . empty ( ) & & ( ! g_Config . bDumpFrames | | ! g_Config . bDumpVideoOutput ) ) {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( status = = SaveState : : Status : : SUCCESS ? OSDType : : MESSAGE_SUCCESS : OSDType : : MESSAGE_ERROR , message , status = = SaveState : : Status : : SUCCESS ? 2.0 : 5.0 ) ;
2016-05-27 21:25:05 -07:00
}
}
2024-01-19 13:44:49 +01:00
static void AfterStateBoot ( SaveState : : Status status , std : : string_view message , void * ignored ) {
2018-06-14 17:52:44 -07:00
AfterSaveStateAction ( status , message , ignored ) ;
2024-11-01 22:52:47 +01:00
Core_Resume ( ) ;
2023-03-21 11:21:19 +01:00
System_Notify ( SystemNotification : : DISASSEMBLY ) ;
2014-06-14 16:13:35 -07:00
}
2023-11-26 19:49:02 +01:00
void EmuScreen : : focusChanged ( ScreenFocusChange focusChange ) {
Screen : : focusChanged ( focusChange ) ;
std : : string gameID = g_paramSFO . GetValueString ( " DISC_ID " ) ;
if ( gameID . empty ( ) ) {
// startup or shutdown
return ;
}
switch ( focusChange ) {
case ScreenFocusChange : : FOCUS_LOST_TOP :
g_Config . TimeTracker ( ) . Stop ( gameID ) ;
2024-01-29 18:41:43 +01:00
controlMapper_ . ReleaseAll ( ) ;
2023-11-26 19:49:02 +01:00
break ;
case ScreenFocusChange : : FOCUS_BECAME_TOP :
g_Config . TimeTracker ( ) . Start ( gameID ) ;
break ;
}
}
2023-09-30 11:21:22 +02:00
void EmuScreen : : sendMessage ( UIMessage message , const char * value ) {
2013-03-29 18:50:08 +01:00
// External commands, like from the Windows UI.
2023-09-30 11:21:22 +02:00
if ( message = = UIMessage : : REQUEST_GAME_PAUSE & & screenManager ( ) - > topScreen ( ) = = this ) {
2013-08-18 20:22:30 +02:00
screenManager ( ) - > push ( new GamePauseScreen ( gamePath_ ) ) ;
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : REQUEST_GAME_STOP ) {
2013-10-12 01:40:33 -07:00
// We will push MainScreen in update().
PSP_Shutdown ( ) ;
2014-05-15 22:17:19 -07:00
bootPending_ = false ;
2017-11-13 15:45:31 +01:00
stopRender_ = true ;
2014-05-11 10:57:33 -07:00
invalid_ = true ;
2023-03-21 11:21:19 +01:00
System_Notify ( SystemNotification : : DISASSEMBLY ) ;
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : REQUEST_GAME_RESET ) {
2013-03-29 20:51:14 +01:00
PSP_Shutdown ( ) ;
2014-05-15 22:17:19 -07:00
bootPending_ = true ;
2014-05-11 10:57:33 -07:00
invalid_ = true ;
2023-03-21 11:21:19 +01:00
System_Notify ( SystemNotification : : DISASSEMBLY ) ;
2014-07-06 14:02:45 -07:00
2013-03-29 20:51:14 +01:00
std : : string resetError ;
2014-05-04 19:56:33 -07:00
if ( ! PSP_InitStart ( PSP_CoreParameter ( ) , & resetError ) ) {
2024-07-14 14:42:59 +02:00
ERROR_LOG ( Log : : Loader , " Error resetting: %s " , resetError . c_str ( ) ) ;
2017-11-13 16:38:35 +01:00
stopRender_ = true ;
2013-08-18 20:14:33 +02:00
screenManager ( ) - > switchScreen ( new MainScreen ( ) ) ;
2013-03-29 20:51:14 +01:00
return ;
}
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : REQUEST_GAME_BOOT ) {
2024-05-14 00:04:40 +02:00
// TODO: Ignore or not if it's the same game that's already running?
if ( gamePath_ = = Path ( value ) ) {
2024-07-14 14:42:59 +02:00
WARN_LOG ( Log : : Loader , " Game already running, ignoring " ) ;
2024-05-14 00:04:40 +02:00
return ;
}
2014-06-14 16:13:35 -07:00
const char * ext = strrchr ( value , ' . ' ) ;
2015-02-28 16:05:13 -08:00
if ( ext ! = nullptr & & ! strcmp ( ext , " .ppst " ) ) {
2021-05-06 01:31:38 +02:00
SaveState : : Load ( Path ( value ) , - 1 , & AfterStateBoot ) ;
2014-06-14 16:13:35 -07:00
} else {
PSP_Shutdown ( ) ;
bootPending_ = true ;
2021-05-06 01:31:38 +02:00
gamePath_ = Path ( value ) ;
2021-01-07 23:16:17 -08:00
// Don't leave it on CORE_POWERDOWN, we'll sometimes aggressively bail.
Core_UpdateState ( CORE_POWERUP ) ;
2014-06-14 16:13:35 -07:00
}
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : CONFIG_LOADED ) {
2017-12-09 14:11:39 -08:00
// In case we need to position touch controls differently.
RecreateViews ( ) ;
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : SHOW_CONTROL_MAPPING & & screenManager ( ) - > topScreen ( ) = = this ) {
2018-04-30 18:57:25 -07:00
UpdateUIState ( UISTATE_PAUSEMENU ) ;
2022-11-22 22:53:54 +01:00
screenManager ( ) - > push ( new ControlMappingScreen ( gamePath_ ) ) ;
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : SHOW_DISPLAY_LAYOUT_EDITOR & & screenManager ( ) - > topScreen ( ) = = this ) {
2018-04-30 18:57:25 -07:00
UpdateUIState ( UISTATE_PAUSEMENU ) ;
2022-11-22 14:16:24 +01:00
screenManager ( ) - > push ( new DisplayLayoutScreen ( gamePath_ ) ) ;
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : SHOW_SETTINGS & & screenManager ( ) - > topScreen ( ) = = this ) {
2018-04-30 18:57:25 -07:00
UpdateUIState ( UISTATE_PAUSEMENU ) ;
2013-09-07 11:29:44 -04:00
screenManager ( ) - > push ( new GameSettingsScreen ( gamePath_ ) ) ;
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : REQUEST_GPU_DUMP_NEXT_FRAME ) {
2015-05-21 10:49:47 +02:00
if ( gpu )
gpu - > DumpNextFrame ( ) ;
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : REQUEST_CLEAR_JIT ) {
2014-12-12 23:48:48 +01:00
currentMIPS - > ClearJitCache ( ) ;
2014-05-27 23:02:28 -07:00
if ( PSP_IsInited ( ) ) {
2016-05-08 01:43:27 +02:00
currentMIPS - > UpdateCore ( ( CPUCore ) g_Config . iCpuCore ) ;
2014-05-27 23:02:28 -07:00
}
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : WINDOW_MINIMIZED ) {
2014-06-29 18:06:47 -04:00
if ( ! strcmp ( value , " true " ) ) {
gstate_c . skipDrawReason | = SKIPDRAW_WINDOW_MINIMIZED ;
} else {
gstate_c . skipDrawReason & = ~ SKIPDRAW_WINDOW_MINIMIZED ;
}
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : SHOW_CHAT_SCREEN ) {
2021-09-15 00:12:33 -07:00
if ( g_Config . bEnableNetworkChat ) {
if ( ! chatButton_ )
RecreateViews ( ) ;
2020-03-03 00:23:12 +07:00
2024-10-02 16:08:12 +02:00
if ( System_GetPropertyInt ( SYSPROP_DEVICE_TYPE ) = = DEVICE_TYPE_DESKTOP ) {
// temporary workaround for hotkey its freeze the ui when open chat screen using hotkey and native keyboard is enable
if ( g_Config . bBypassOSKWithKeyboard ) {
// TODO: Make translatable.
g_OSD . Show ( OSDType : : MESSAGE_INFO , " Disable \" Use system native keyboard \" to use ctrl + c hotkey " , 2.0f ) ;
} else {
UI : : EventParams e { } ;
OnChatMenu . Trigger ( e ) ;
}
2021-09-15 00:12:33 -07:00
} else {
2017-07-08 18:08:33 +08:00
UI : : EventParams e { } ;
OnChatMenu . Trigger ( e ) ;
2017-06-08 02:18:45 +08:00
}
2021-09-15 00:12:33 -07:00
}
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : APP_RESUMED & & screenManager ( ) - > topScreen ( ) = = this ) {
2021-08-11 23:26:39 +02:00
if ( System_GetPropertyInt ( SYSPROP_DEVICE_TYPE ) = = DEVICE_TYPE_TV ) {
if ( ! KeyMap : : IsKeyMapped ( DEVICE_ID_PAD_0 , VIRTKEY_PAUSE ) | | ! KeyMap : : IsKeyMapped ( DEVICE_ID_PAD_1 , VIRTKEY_PAUSE ) ) {
// If it's a TV (so no built-in back button), and there's no back button mapped to a pad,
// use this as the fallback way to get into the menu.
2021-08-11 09:07:04 +02:00
2021-08-11 23:26:39 +02:00
screenManager ( ) - > push ( new GamePauseScreen ( gamePath_ ) ) ;
}
}
2023-09-30 11:21:22 +02:00
} else if ( message = = UIMessage : : REQUEST_PLAY_SOUND ) {
2024-01-28 11:22:19 +01:00
if ( g_Config . bAchievementsSoundEffects & & g_Config . bEnableSound ) {
float achievementVolume = g_Config . iAchievementSoundVolume * 0.1f ;
2023-07-12 19:18:56 +02:00
// TODO: Handle this some nicer way.
if ( ! strcmp ( value , " achievement_unlocked " ) ) {
2024-01-28 11:22:19 +01:00
g_BackgroundAudio . SFX ( ) . Play ( UI : : UISound : : ACHIEVEMENT_UNLOCKED , achievementVolume * 1.0f ) ;
2023-07-12 19:18:56 +02:00
}
if ( ! strcmp ( value , " leaderboard_submitted " ) ) {
2024-01-28 11:22:19 +01:00
g_BackgroundAudio . SFX ( ) . Play ( UI : : UISound : : LEADERBOARD_SUBMITTED , achievementVolume * 1.0f ) ;
2023-07-12 19:18:56 +02:00
}
}
2013-11-02 13:33:27 -07:00
}
2013-03-29 18:50:08 +01:00
}
2023-09-04 10:58:11 +02:00
bool EmuScreen : : UnsyncTouch ( const TouchInput & touch ) {
2023-08-10 13:21:36 +02:00
System_Notify ( SystemNotification : : ACTIVITY ) ;
2015-02-28 22:20:14 -08:00
2021-11-19 16:12:26 +01:00
if ( chatMenu_ & & chatMenu_ - > GetVisibility ( ) = = UI : : V_VISIBLE ) {
// Avoid pressing touch button behind the chat
if ( chatMenu_ - > Contains ( touch . x , touch . y ) ) {
chatMenu_ - > Touch ( touch ) ;
2023-09-04 10:58:11 +02:00
return true ;
2021-11-19 16:12:26 +01:00
} else if ( ( touch . flags & TOUCH_DOWN ) ! = 0 ) {
chatMenu_ - > Close ( ) ;
if ( chatButton_ )
chatButton_ - > SetVisibility ( UI : : V_VISIBLE ) ;
UI : : EnableFocusMovement ( false ) ;
}
2021-09-12 19:44:44 -07:00
}
2024-11-12 12:20:14 +01:00
if ( ! ( g_Config . bShowImDebugger & & imguiInited_ ) ) {
2024-10-30 23:59:57 +01:00
GamepadTouch ( ) ;
}
2023-12-29 17:07:49 +01:00
2014-06-15 13:04:59 +02:00
if ( root_ ) {
2023-11-11 11:21:36 +01:00
UIScreen : : UnsyncTouch ( touch ) ;
2014-06-15 13:04:59 +02:00
}
2023-09-04 10:58:11 +02:00
return true ;
2013-07-06 19:08:59 +02:00
}
2023-03-30 10:47:28 +02:00
void EmuScreen : : onVKey ( int virtualKeyCode , bool down ) {
2023-04-06 00:34:50 +02:00
auto sc = GetI18NCategory ( I18NCat : : SCREEN ) ;
2023-04-20 00:00:46 +02:00
auto mc = GetI18NCategory ( I18NCat : : MAPPABLECONTROLS ) ;
2013-07-07 14:08:08 +02:00
2013-07-07 10:42:39 +02:00
switch ( virtualKeyCode ) {
2024-11-04 23:33:03 +01:00
case VIRTKEY_TOGGLE_DEBUGGER :
if ( down ) {
2024-11-12 12:20:14 +01:00
g_Config . bShowImDebugger = ! g_Config . bShowImDebugger ;
2024-11-04 23:33:03 +01:00
}
break ;
2021-08-17 16:48:47 +02:00
case VIRTKEY_FASTFORWARD :
2023-03-30 10:47:28 +02:00
if ( down ) {
if ( coreState = = CORE_STEPPING ) {
2024-11-01 22:52:47 +01:00
Core_Resume ( ) ;
2023-03-30 10:47:28 +02:00
}
PSP_CoreParameter ( ) . fastForward = true ;
} else {
PSP_CoreParameter ( ) . fastForward = false ;
2018-06-22 21:33:12 -07:00
}
2013-07-20 14:05:07 +02:00
break ;
2013-07-07 14:08:08 +02:00
case VIRTKEY_SPEED_TOGGLE :
2023-07-11 11:29:04 +02:00
if ( down ) {
2023-03-30 10:47:28 +02:00
// Cycle through enabled speeds.
if ( PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : NORMAL & & g_Config . iFpsLimit1 > = 0 ) {
PSP_CoreParameter ( ) . fpsLimit = FPSLimit : : CUSTOM1 ;
2023-10-01 17:59:43 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " fixed " , " Speed: alternate " ) , 1.0 , " altspeed " ) ;
2023-03-30 10:47:28 +02:00
} else if ( PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : CUSTOM1 & & g_Config . iFpsLimit2 > = 0 ) {
PSP_CoreParameter ( ) . fpsLimit = FPSLimit : : CUSTOM2 ;
2023-10-01 17:59:43 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " SpeedCustom2 " , " Speed: alternate 2 " ) , 1.0 , " altspeed " ) ;
2023-03-30 10:47:28 +02:00
} else if ( PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : CUSTOM1 | | PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : CUSTOM2 ) {
PSP_CoreParameter ( ) . fpsLimit = FPSLimit : : NORMAL ;
2023-10-01 17:59:43 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " standard " , " Speed: standard " ) , 1.0 , " altspeed " ) ;
2023-03-30 10:47:28 +02:00
}
2013-07-07 14:08:08 +02:00
}
break ;
2013-07-08 17:46:20 +02:00
2018-06-16 20:07:11 -07:00
case VIRTKEY_SPEED_CUSTOM1 :
2023-07-11 11:29:04 +02:00
if ( down ) {
if ( PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : NORMAL ) {
PSP_CoreParameter ( ) . fpsLimit = FPSLimit : : CUSTOM1 ;
2023-10-01 17:59:43 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " fixed " , " Speed: alternate " ) , 1.0 , " altspeed " ) ;
2023-07-11 11:29:04 +02:00
}
} else {
if ( PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : CUSTOM1 ) {
PSP_CoreParameter ( ) . fpsLimit = FPSLimit : : NORMAL ;
2023-10-01 17:59:43 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " standard " , " Speed: standard " ) , 1.0 , " altspeed " ) ;
2023-03-30 10:47:28 +02:00
}
2018-06-16 18:22:34 -07:00
}
break ;
2018-06-16 20:07:11 -07:00
case VIRTKEY_SPEED_CUSTOM2 :
2023-07-11 11:29:04 +02:00
if ( down ) {
if ( PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : NORMAL ) {
PSP_CoreParameter ( ) . fpsLimit = FPSLimit : : CUSTOM2 ;
2023-10-01 17:59:43 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " SpeedCustom2 " , " Speed: alternate 2 " ) , 1.0 , " altspeed " ) ;
2023-07-11 11:29:04 +02:00
}
} else {
if ( PSP_CoreParameter ( ) . fpsLimit = = FPSLimit : : CUSTOM2 ) {
PSP_CoreParameter ( ) . fpsLimit = FPSLimit : : NORMAL ;
2023-10-01 17:59:43 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " standard " , " Speed: standard " ) , 1.0 , " altspeed " ) ;
2023-03-30 10:47:28 +02:00
}
2018-06-16 20:07:11 -07:00
}
break ;
2018-06-16 18:22:34 -07:00
2013-07-07 14:08:08 +02:00
case VIRTKEY_PAUSE :
2023-03-30 10:47:28 +02:00
if ( down ) {
2023-05-02 21:36:17 +02:00
// Trigger on key-up to partially avoid repetition problems.
// This is needed whenever we pop up a menu since the mapper
// might miss the key-up. Same as VIRTKEY_OPENCHAT.
2023-03-30 10:47:28 +02:00
pauseTrigger_ = true ;
2023-05-02 21:36:17 +02:00
controlMapper_ . ForceReleaseVKey ( virtualKeyCode ) ;
2023-03-30 10:47:28 +02:00
}
2013-07-07 14:08:08 +02:00
break ;
2013-07-07 16:25:15 -07:00
2016-08-28 00:20:03 -04:00
case VIRTKEY_FRAME_ADVANCE :
2024-09-18 15:17:20 +02:00
// Can't do this reliably in an async fashion, so we just set a variable.
if ( down ) {
doFrameAdvance_ . store ( true ) ;
2016-08-28 00:20:03 -04:00
}
break ;
2017-06-08 02:26:49 +08:00
case VIRTKEY_OPENCHAT :
2023-05-02 21:36:17 +02:00
if ( down & & g_Config . bEnableNetworkChat ) {
2017-07-08 18:08:33 +08:00
UI : : EventParams e { } ;
OnChatMenu . Trigger ( e ) ;
2023-05-02 21:36:17 +02:00
controlMapper_ . ForceReleaseVKey ( virtualKeyCode ) ;
2017-06-08 02:26:49 +08:00
}
break ;
2014-11-07 22:40:53 +10:00
case VIRTKEY_AXIS_SWAP :
2023-03-30 10:47:28 +02:00
if ( down ) {
2023-04-20 00:00:46 +02:00
controlMapper_ . ToggleSwapAxes ( ) ;
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , mc - > T ( " AxisSwap " ) ) ; // best string we have.
2023-03-30 10:47:28 +02:00
}
2014-11-07 22:40:53 +10:00
break ;
2015-07-05 16:09:29 -07:00
case VIRTKEY_DEVMENU :
2023-03-30 10:47:28 +02:00
if ( down ) {
UI : : EventParams e { } ;
OnDevMenu . Trigger ( e ) ;
}
2015-07-05 16:09:29 -07:00
break ;
2024-09-18 14:18:04 +02:00
case VIRTKEY_RESET_EMULATION :
System_PostUIMessage ( UIMessage : : REQUEST_GAME_RESET ) ;
break ;
2017-12-01 23:48:58 +01:00
# ifndef MOBILE_DEVICE
case VIRTKEY_RECORD :
2023-03-30 10:47:28 +02:00
if ( down ) {
if ( g_Config . bDumpFrames = = g_Config . bDumpAudio ) {
g_Config . bDumpFrames = ! g_Config . bDumpFrames ;
g_Config . bDumpAudio = ! g_Config . bDumpAudio ;
2017-12-01 23:48:58 +01:00
} else {
2023-03-30 10:47:28 +02:00
// This hotkey should always toggle both audio and video together.
// So let's make sure that's the only outcome even if video OR audio was already being dumped.
if ( g_Config . bDumpFrames ) {
AVIDump : : Stop ( ) ;
AVIDump : : Start ( PSP_CoreParameter ( ) . renderWidth , PSP_CoreParameter ( ) . renderHeight ) ;
g_Config . bDumpAudio = true ;
} else {
WAVDump : : Reset ( ) ;
g_Config . bDumpFrames = true ;
}
2017-12-01 23:48:58 +01:00
}
}
break ;
# endif
2013-12-05 16:15:33 +01:00
case VIRTKEY_REWIND :
2023-12-03 16:41:29 +01:00
if ( down & & ! Achievements : : WarnUserIfHardcoreModeActive ( false ) ) {
2023-03-30 10:47:28 +02:00
if ( SaveState : : CanRewind ( ) ) {
SaveState : : Rewind ( & AfterSaveStateAction ) ;
} else {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , sc - > T ( " norewind " , " No rewind save states available " ) , 2.0 ) ;
2023-03-30 10:47:28 +02:00
}
2013-12-05 16:15:33 +01:00
}
break ;
2013-12-06 15:46:56 +01:00
case VIRTKEY_SAVE_STATE :
2023-12-03 16:41:29 +01:00
if ( down & & ! Achievements : : WarnUserIfHardcoreModeActive ( true ) ) {
2023-03-30 10:47:28 +02:00
SaveState : : SaveSlot ( gamePath_ , g_Config . iCurrentStateSlot , & AfterSaveStateAction ) ;
2023-11-16 20:13:47 +01:00
}
2013-12-06 15:46:56 +01:00
break ;
case VIRTKEY_LOAD_STATE :
2023-12-03 16:41:29 +01:00
if ( down & & ! Achievements : : WarnUserIfHardcoreModeActive ( false ) ) {
2023-03-30 10:47:28 +02:00
SaveState : : LoadSlot ( gamePath_ , g_Config . iCurrentStateSlot , & AfterSaveStateAction ) ;
2023-11-16 20:13:47 +01:00
}
2013-12-06 15:46:56 +01:00
break ;
2023-05-25 11:32:49 +00:00
case VIRTKEY_PREVIOUS_SLOT :
2023-12-03 16:41:29 +01:00
if ( down & & ! Achievements : : WarnUserIfHardcoreModeActive ( true ) ) {
2023-05-25 11:32:49 +00:00
SaveState : : PrevSlot ( ) ;
2023-09-30 11:21:22 +02:00
System_PostUIMessage ( UIMessage : : SAVESTATE_DISPLAY_SLOT ) ;
2023-05-25 11:32:49 +00:00
}
break ;
2014-01-07 15:56:04 +01:00
case VIRTKEY_NEXT_SLOT :
2023-12-03 16:41:29 +01:00
if ( down & & ! Achievements : : WarnUserIfHardcoreModeActive ( true ) ) {
2023-03-30 10:47:28 +02:00
SaveState : : NextSlot ( ) ;
2023-09-30 11:21:22 +02:00
System_PostUIMessage ( UIMessage : : SAVESTATE_DISPLAY_SLOT ) ;
2023-03-30 10:47:28 +02:00
}
2014-01-07 15:56:04 +01:00
break ;
2014-01-03 15:16:23 +01:00
case VIRTKEY_TOGGLE_FULLSCREEN :
2023-03-30 10:47:28 +02:00
if ( down )
System_ToggleFullscreenState ( " " ) ;
2014-01-03 15:16:23 +01:00
break ;
2023-12-29 17:37:34 +01:00
case VIRTKEY_TOGGLE_TOUCH_CONTROLS :
if ( down ) {
if ( g_Config . bShowTouchControls ) {
// This just messes with opacity if enabled, so you can touch the screen again to bring them back.
if ( GamepadGetOpacity ( ) < 0.01f ) {
GamepadTouch ( ) ;
} else {
// Reset.
GamepadTouch ( true ) ;
}
} else {
// If touch controls are disabled though, they'll get enabled.
g_Config . bShowTouchControls = true ;
RecreateViews ( ) ;
GamepadTouch ( ) ;
}
}
break ;
case VIRTKEY_TOGGLE_MOUSE :
if ( down ) {
g_Config . bMouseControl = ! g_Config . bMouseControl ;
}
break ;
2019-04-30 19:01:20 -07:00
case VIRTKEY_SCREENSHOT :
2023-03-30 10:47:28 +02:00
if ( down )
g_TakeScreenshot = true ;
2019-04-30 19:01:20 -07:00
break ;
2019-03-26 06:12:02 +01:00
case VIRTKEY_TEXTURE_DUMP :
2023-03-30 10:47:28 +02:00
if ( down ) {
g_Config . bSaveNewTextures = ! g_Config . bSaveNewTextures ;
if ( g_Config . bSaveNewTextures ) {
2024-09-24 14:01:24 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " saveNewTextures_true " , " Textures will now be saved to your storage " ) , 2.0 , " savetexturechanged " ) ;
2023-09-30 11:21:22 +02:00
System_PostUIMessage ( UIMessage : : GPU_CONFIG_CHANGED ) ;
2023-03-30 10:47:28 +02:00
} else {
2024-09-24 14:01:24 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " saveNewTextures_false " , " Texture saving was disabled " ) , 2.0 , " savetexturechanged " ) ;
2023-03-30 10:47:28 +02:00
}
2019-03-26 06:12:02 +01:00
}
break ;
case VIRTKEY_TEXTURE_REPLACE :
2023-03-30 10:47:28 +02:00
if ( down ) {
g_Config . bReplaceTextures = ! g_Config . bReplaceTextures ;
if ( g_Config . bReplaceTextures )
2024-09-24 14:01:24 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " replaceTextures_true " , " Texture replacement enabled " ) , 2.0 , " replacetexturechanged " ) ;
2023-03-30 10:47:28 +02:00
else
2024-09-24 14:01:24 +02:00
g_OSD . Show ( OSDType : : MESSAGE_INFO , sc - > T ( " replaceTextures_false " , " Textures are no longer being replaced " ) , 2.0 , " replacetexturechanged " ) ;
2023-09-30 11:21:22 +02:00
System_PostUIMessage ( UIMessage : : GPU_CONFIG_CHANGED ) ;
2023-03-30 10:47:28 +02:00
}
2019-03-26 06:12:02 +01:00
break ;
2020-01-28 08:52:18 +01:00
case VIRTKEY_RAPID_FIRE :
2023-07-23 11:49:25 +02:00
__CtrlSetRapidFire ( down , g_Config . iRapidFireInterval ) ;
2020-01-28 08:52:18 +01:00
break ;
2020-02-25 12:26:23 +01:00
case VIRTKEY_MUTE_TOGGLE :
2023-03-30 10:47:28 +02:00
if ( down )
g_Config . bEnableSound = ! g_Config . bEnableSound ;
2020-02-25 12:26:23 +01:00
break ;
2022-04-23 08:52:51 +02:00
case VIRTKEY_SCREEN_ROTATION_VERTICAL :
2023-03-30 10:47:28 +02:00
if ( down )
g_Config . iInternalScreenRotation = ROTATION_LOCKED_VERTICAL ;
2022-04-23 08:52:51 +02:00
break ;
case VIRTKEY_SCREEN_ROTATION_VERTICAL180 :
2023-03-30 10:47:28 +02:00
if ( down )
g_Config . iInternalScreenRotation = ROTATION_LOCKED_VERTICAL180 ;
2022-04-23 08:52:51 +02:00
break ;
case VIRTKEY_SCREEN_ROTATION_HORIZONTAL :
2023-03-30 10:47:28 +02:00
if ( down )
g_Config . iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL ;
2022-04-23 08:52:51 +02:00
break ;
case VIRTKEY_SCREEN_ROTATION_HORIZONTAL180 :
2023-03-30 10:47:28 +02:00
if ( down )
g_Config . iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL180 ;
2013-07-07 10:42:39 +02:00
break ;
2023-08-23 22:14:51 +02:00
case VIRTKEY_TOGGLE_WLAN :
if ( down ) {
auto n = GetI18NCategory ( I18NCat : : NETWORKING ) ;
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
g_Config . bEnableWlan = ! g_Config . bEnableWlan ;
// Try to avoid adding more strings so we piece together a message from existing ones.
g_OSD . Show ( OSDType : : MESSAGE_INFO , StringFromFormat (
" %s: %s " , n - > T ( " Enable networking " ) , g_Config . bEnableWlan ? di - > T ( " Enabled " ) : di - > T ( " Disabled " ) ) , 2.0 , " toggle_wlan " ) ;
}
break ;
2023-10-04 14:10:14 +02:00
case VIRTKEY_EXIT_APP :
System_ExitApp ( ) ;
break ;
2013-07-07 10:42:39 +02:00
}
}
2023-03-30 15:03:41 +02:00
void EmuScreen : : onVKeyAnalog ( int virtualKeyCode , float value ) {
2023-03-30 15:11:34 +02:00
if ( virtualKeyCode ! = VIRTKEY_SPEED_ANALOG ) {
return ;
}
// We only handle VIRTKEY_SPEED_ANALOG here.
2023-03-31 20:27:30 +02:00
// Xbox controllers need a pretty big deadzone here to not leave behind small values
// on occasion when releasing the trigger. Still feels right.
2023-04-15 17:36:55 +02:00
static constexpr float DEADZONE_THRESHOLD = 0.2f ;
static constexpr float DEADZONE_SCALE = 1.0f / ( 1.0f - DEADZONE_THRESHOLD ) ;
2023-03-30 15:11:34 +02:00
FPSLimit & limitMode = PSP_CoreParameter ( ) . fpsLimit ;
// If we're using an alternate speed already, let that win.
if ( limitMode ! = FPSLimit : : NORMAL & & limitMode ! = FPSLimit : : ANALOG )
return ;
// Don't even try if the limit is invalid.
if ( g_Config . iAnalogFpsLimit < = 0 )
return ;
// Apply a small deadzone (against the resting position.)
value = std : : max ( 0.0f , ( value - DEADZONE_THRESHOLD ) * DEADZONE_SCALE ) ;
// If target is above 60, value is how much to speed up over 60. Otherwise, it's how much slower.
// So normalize the target.
int target = g_Config . iAnalogFpsLimit - 60 ;
PSP_CoreParameter ( ) . analogFpsLimit = 60 + ( int ) ( target * value ) ;
2023-03-30 15:03:41 +02:00
2023-03-30 15:11:34 +02:00
// If we've reset back to normal, turn it off.
limitMode = PSP_CoreParameter ( ) . analogFpsLimit = = 60 ? FPSLimit : : NORMAL : FPSLimit : : ANALOG ;
2023-03-30 15:03:41 +02:00
}
2023-05-26 11:49:50 +02:00
bool EmuScreen : : UnsyncKey ( const KeyInput & key ) {
2023-08-10 13:21:36 +02:00
System_Notify ( SystemNotification : : ACTIVITY ) ;
2024-11-12 12:20:14 +01:00
if ( UI : : IsFocusMovementEnabled ( ) | | ( g_Config . bShowImDebugger & & imguiInited_ ) ) {
2024-11-04 23:33:03 +01:00
// Note: Allow some Vkeys through, so we can toggle the imgui for example (since we actually block the control mapper otherwise in imgui mode).
// We need to manually implement it here :/
2024-11-12 12:20:14 +01:00
if ( g_Config . bShowImDebugger & & imguiInited_ & & ( key . flags & ( KEY_UP | KEY_DOWN ) ) ) {
2024-11-04 23:33:03 +01:00
InputMapping mapping ( key . deviceId , key . keyCode ) ;
std : : vector < int > pspButtons ;
bool mappingFound = KeyMap : : InputMappingToPspButton ( mapping , & pspButtons ) ;
if ( mappingFound ) {
for ( auto b : pspButtons ) {
2024-11-05 01:03:21 +01:00
if ( b = = VIRTKEY_TOGGLE_DEBUGGER | | b = = VIRTKEY_PAUSE ) {
return controlMapper_ . Key ( key , & pauseTrigger_ ) ;
2024-11-04 23:33:03 +01:00
}
}
}
}
2015-02-28 22:20:14 -08:00
2023-09-12 10:25:04 +02:00
return UIScreen : : UnsyncKey ( key ) ;
2021-09-12 19:41:47 -07:00
}
2021-07-08 21:30:23 +02:00
return controlMapper_ . Key ( key , & pauseTrigger_ ) ;
2013-07-06 19:08:59 +02:00
}
2023-09-12 10:25:04 +02:00
bool EmuScreen : : key ( const KeyInput & key ) {
bool retval = UIScreen : : key ( key ) ;
2024-11-12 12:20:14 +01:00
if ( ! retval & & g_Config . bShowImDebugger & & imguiInited_ ) {
2024-10-30 23:59:57 +01:00
ImGui_ImplPlatform_KeyEvent ( key ) ;
}
2023-09-12 10:25:04 +02:00
if ( ! retval & & ( key . flags & KEY_DOWN ) ! = 0 & & UI : : IsEscapeKey ( key ) ) {
if ( chatMenu_ )
chatMenu_ - > Close ( ) ;
if ( chatButton_ )
chatButton_ - > SetVisibility ( UI : : V_VISIBLE ) ;
UI : : EnableFocusMovement ( false ) ;
return true ;
}
return retval ;
}
2024-10-30 23:59:57 +01:00
void EmuScreen : : touch ( const TouchInput & touch ) {
2024-11-12 12:20:14 +01:00
if ( g_Config . bShowImDebugger & & imguiInited_ ) {
2024-10-30 23:59:57 +01:00
ImGui_ImplPlatform_TouchEvent ( touch ) ;
} else {
UIScreen : : touch ( touch ) ;
}
}
2023-09-27 17:34:34 +02:00
void EmuScreen : : UnsyncAxis ( const AxisInput * axes , size_t count ) {
2023-08-10 13:21:36 +02:00
System_Notify ( SystemNotification : : ACTIVITY ) ;
2023-11-11 11:21:36 +01:00
if ( UI : : IsFocusMovementEnabled ( ) ) {
return UIScreen : : UnsyncAxis ( axes , count ) ;
}
2023-09-27 17:34:34 +02:00
return controlMapper_ . Axis ( axes , count ) ;
2013-07-06 19:08:59 +02:00
}
2018-01-01 21:51:09 -08:00
class GameInfoBGView : public UI : : InertView {
public :
2021-05-06 01:31:38 +02:00
GameInfoBGView ( const Path & gamePath , UI : : LayoutParams * layoutParams ) : InertView ( layoutParams ) , gamePath_ ( gamePath ) {
2018-01-01 21:51:09 -08:00
}
2021-03-09 00:09:36 +01:00
void Draw ( UIContext & dc ) override {
2018-01-01 21:51:09 -08:00
// Should only be called when visible.
2024-01-28 16:23:27 +01:00
std : : shared_ptr < GameInfo > ginfo = g_gameInfoCache - > GetInfo ( dc . GetDrawContext ( ) , gamePath_ , GameInfoFlags : : BG ) ;
2018-01-01 21:51:09 -08:00
dc . Flush ( ) ;
// PIC1 is the loading image, so let's only draw if it's available.
2024-01-28 16:56:07 +01:00
if ( ginfo - > Ready ( GameInfoFlags : : BG ) & & ginfo - > pic1 . texture ) {
2023-12-12 22:34:31 +01:00
Draw : : Texture * texture = ginfo - > pic1 . texture ;
2018-05-27 21:54:07 +02:00
if ( texture ) {
dc . GetDrawContext ( ) - > BindTexture ( 0 , texture ) ;
double loadTime = ginfo - > pic1 . timeLoaded ;
uint32_t color = alphaMul ( color_ , ease ( ( time_now_d ( ) - loadTime ) * 3 ) ) ;
dc . Draw ( ) - > DrawTexRect ( dc . GetBounds ( ) , 0 , 0 , 1 , 1 , color ) ;
dc . Flush ( ) ;
dc . RebindTexture ( ) ;
}
2018-01-01 21:51:09 -08:00
}
}
2021-02-21 16:38:02 -08:00
std : : string DescribeText ( ) const override {
return " " ;
}
2018-01-01 21:51:09 -08:00
void SetColor ( uint32_t c ) {
color_ = c ;
}
protected :
2021-05-06 01:31:38 +02:00
Path gamePath_ ;
2018-01-01 21:51:09 -08:00
uint32_t color_ = 0xFFC0C0C0 ;
} ;
2023-04-05 23:47:51 +02:00
// TODO: Shouldn't actually need bounds for this, Anchor can center too.
static UI : : AnchorLayoutParams * AnchorInCorner ( const Bounds & bounds , int corner , float xOffset , float yOffset ) {
using namespace UI ;
2023-07-16 11:03:49 +02:00
switch ( ( ScreenEdgePosition ) g_Config . iChatButtonPosition ) {
case ScreenEdgePosition : : BOTTOM_LEFT : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , xOffset , NONE , NONE , yOffset , true ) ;
case ScreenEdgePosition : : BOTTOM_CENTER : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , bounds . centerX ( ) , NONE , NONE , yOffset , true ) ;
2023-08-07 21:38:03 +02:00
case ScreenEdgePosition : : BOTTOM_RIGHT : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , NONE , NONE , xOffset , yOffset , true ) ;
2023-07-16 11:03:49 +02:00
case ScreenEdgePosition : : TOP_LEFT : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , xOffset , yOffset , NONE , NONE , true ) ;
case ScreenEdgePosition : : TOP_CENTER : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , bounds . centerX ( ) , yOffset , NONE , NONE , true ) ;
case ScreenEdgePosition : : TOP_RIGHT : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , NONE , yOffset , xOffset , NONE , true ) ;
case ScreenEdgePosition : : CENTER_LEFT : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , xOffset , bounds . centerY ( ) , NONE , NONE , true ) ;
case ScreenEdgePosition : : CENTER_RIGHT : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , NONE , bounds . centerY ( ) , xOffset , NONE , true ) ;
2023-04-05 23:47:51 +02:00
default : return new AnchorLayoutParams ( WRAP_CONTENT , WRAP_CONTENT , xOffset , NONE , NONE , yOffset , true ) ;
}
}
2013-07-20 12:06:06 +02:00
void EmuScreen : : CreateViews ( ) {
2015-02-01 18:04:06 +01:00
using namespace UI ;
2017-12-03 10:39:25 -08:00
2024-10-03 18:55:22 +02:00
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
2023-04-06 00:34:50 +02:00
auto dev = GetI18NCategory ( I18NCat : : DEVELOPER ) ;
auto sc = GetI18NCategory ( I18NCat : : SCREEN ) ;
2017-12-03 10:39:25 -08:00
2020-03-31 00:47:01 +02:00
const Bounds & bounds = screenManager ( ) - > getUIContext ( ) - > GetLayoutBounds ( ) ;
2014-02-10 15:55:21 +01:00
InitPadLayout ( bounds . w , bounds . h ) ;
2021-08-28 20:06:05 +02:00
// Devices without a back button like iOS need an on-screen touch back button.
bool showPauseButton = ! System_GetPropertyBool ( SYSPROP_HAS_BACK_BUTTON ) | | g_Config . bShowTouchPause ;
root_ = CreatePadLayout ( bounds . w , bounds . h , & pauseTrigger_ , showPauseButton , & controlMapper_ ) ;
2013-09-07 20:54:11 +02:00
if ( g_Config . bShowDeveloperMenu ) {
2017-12-03 10:39:25 -08:00
root_ - > Add ( new Button ( dev - > T ( " DevMenu " ) ) ) - > OnClick . Handle ( this , & EmuScreen : : OnDevTools ) ;
2013-09-07 20:54:11 +02:00
}
2021-08-08 23:03:19 -07:00
LinearLayout * buttons = new LinearLayout ( Orientation : : ORIENT_HORIZONTAL , new AnchorLayoutParams ( bounds . centerX ( ) , NONE , NONE , 60 , true ) ) ;
buttons - > SetSpacing ( 20.0f ) ;
root_ - > Add ( buttons ) ;
resumeButton_ = buttons - > Add ( new Button ( dev - > T ( " Resume " ) ) ) ;
2020-12-19 20:26:02 +01:00
resumeButton_ - > OnClick . Handle ( this , & EmuScreen : : OnResume ) ;
resumeButton_ - > SetVisibility ( V_GONE ) ;
2019-10-25 10:56:01 +02:00
2021-08-08 23:03:19 -07:00
resetButton_ = buttons - > Add ( new Button ( dev - > T ( " Reset " ) ) ) ;
2024-10-03 18:55:22 +02:00
resetButton_ - > OnClick . Add ( [ ] ( UI : : EventParams & ) {
if ( coreState = = CoreState : : CORE_RUNTIME_ERROR ) {
System_PostUIMessage ( UIMessage : : REQUEST_GAME_RESET ) ;
}
return UI : : EVENT_DONE ;
} ) ;
2021-08-08 23:03:19 -07:00
resetButton_ - > SetVisibility ( V_GONE ) ;
2024-10-03 18:55:22 +02:00
backButton_ = buttons - > Add ( new Button ( dev - > T ( " Back " ) ) ) ;
backButton_ - > OnClick . Add ( [ this ] ( UI : : EventParams & ) {
this - > pauseTrigger_ = true ;
return UI : : EVENT_DONE ;
} ) ;
backButton_ - > SetVisibility ( V_GONE ) ;
2019-10-25 10:56:01 +02:00
cardboardDisableButton_ = root_ - > Add ( new Button ( sc - > T ( " Cardboard VR OFF " ) , new AnchorLayoutParams ( bounds . centerX ( ) , NONE , NONE , 30 , true ) ) ) ;
cardboardDisableButton_ - > OnClick . Handle ( this , & EmuScreen : : OnDisableCardboard ) ;
cardboardDisableButton_ - > SetVisibility ( V_GONE ) ;
2020-08-30 17:50:42 +02:00
cardboardDisableButton_ - > SetScale ( 0.65f ) ; // make it smaller - this button can be in the way otherwise.
2019-10-25 10:56:01 +02:00
2023-04-05 23:47:51 +02:00
if ( g_Config . bEnableNetworkChat ) {
if ( g_Config . iChatButtonPosition ! = 8 ) {
2023-12-20 12:35:02 +03:00
auto n = GetI18NCategory ( I18NCat : : NETWORKING ) ;
2023-04-05 23:47:51 +02:00
AnchorLayoutParams * layoutParams = AnchorInCorner ( bounds , g_Config . iChatButtonPosition , 80.0f , 50.0f ) ;
ChoiceWithValueDisplay * btn = new ChoiceWithValueDisplay ( & newChatMessages_ , n - > T ( " Chat " ) , layoutParams ) ;
root_ - > Add ( btn ) - > OnClick . Handle ( this , & EmuScreen : : OnChat ) ;
chatButton_ = btn ;
2016-12-05 11:04:31 +08:00
}
2024-10-02 00:59:57 +02:00
chatMenu_ = root_ - > Add ( new ChatMenu ( GetRequesterToken ( ) , screenManager ( ) - > getUIContext ( ) - > GetBounds ( ) , screenManager ( ) , new LayoutParams ( FILL_PARENT , FILL_PARENT ) ) ) ;
2021-09-12 19:44:44 -07:00
chatMenu_ - > SetVisibility ( UI : : V_GONE ) ;
2021-02-15 20:37:24 -08:00
} else {
chatButton_ = nullptr ;
2021-09-12 19:44:44 -07:00
chatMenu_ = nullptr ;
2016-10-23 00:06:07 +08:00
}
2020-03-02 22:25:18 +07:00
2021-05-06 01:31:38 +02:00
saveStatePreview_ = new AsyncImageFileView ( Path ( ) , IS_FIXED , new AnchorLayoutParams ( bounds . centerX ( ) , 100 , NONE , NONE , true ) ) ;
2015-02-01 18:04:06 +01:00
saveStatePreview_ - > SetFixedSize ( 160 , 90 ) ;
saveStatePreview_ - > SetColor ( 0x90FFFFFF ) ;
saveStatePreview_ - > SetVisibility ( V_GONE ) ;
2015-02-02 10:05:23 +01:00
saveStatePreview_ - > SetCanBeFocused ( false ) ;
2015-02-01 18:04:06 +01:00
root_ - > Add ( saveStatePreview_ ) ;
2017-12-03 11:56:42 -08:00
2018-01-01 21:51:09 -08:00
GameInfoBGView * loadingBG = root_ - > Add ( new GameInfoBGView ( gamePath_ , new AnchorLayoutParams ( FILL_PARENT , FILL_PARENT ) ) ) ;
2018-03-13 11:25:00 +01:00
TextView * loadingTextView = root_ - > Add ( new TextView ( sc - > T ( PSP_GetLoading ( ) ) , new AnchorLayoutParams ( bounds . centerX ( ) , NONE , NONE , 40 , true ) ) ) ;
2018-04-29 14:44:00 -07:00
loadingTextView_ = loadingTextView ;
2018-04-20 09:55:03 +02:00
2020-02-29 21:51:14 +01:00
static const ImageID symbols [ 4 ] = {
ImageID ( " I_CROSS " ) ,
ImageID ( " I_CIRCLE " ) ,
ImageID ( " I_SQUARE " ) ,
ImageID ( " I_TRIANGLE " ) ,
2018-02-08 12:02:44 +01:00
} ;
2020-02-29 21:51:14 +01:00
2018-03-13 11:25:00 +01:00
Spinner * loadingSpinner = root_ - > Add ( new Spinner ( symbols , ARRAY_SIZE ( symbols ) , new AnchorLayoutParams ( NONE , NONE , 45 , 45 , true ) ) ) ;
2018-02-08 12:02:44 +01:00
loadingSpinner_ = loadingSpinner ;
2018-04-29 14:44:00 -07:00
loadingBG - > SetTag ( " LoadingBG " ) ;
loadingTextView - > SetTag ( " LoadingText " ) ;
loadingSpinner - > SetTag ( " LoadingSpinner " ) ;
// Don't really need this, and it creates a lot of strings to translate...
loadingTextView - > SetVisibility ( V_GONE ) ;
2018-01-01 21:51:09 -08:00
loadingTextView - > SetShadow ( true ) ;
2017-12-03 11:56:42 -08:00
2018-04-29 14:44:00 -07:00
loadingViewColor_ = loadingSpinner - > AddTween ( new CallbackColorTween ( 0x00FFFFFF , 0x00FFFFFF , 0.2f , & bezierEaseInOut ) ) ;
2018-02-08 12:02:44 +01:00
loadingViewColor_ - > SetCallback ( [ loadingBG , loadingTextView , loadingSpinner ] ( View * v , uint32_t c ) {
2018-01-01 21:51:09 -08:00
loadingBG - > SetColor ( c & 0xFFC0C0C0 ) ;
loadingTextView - > SetTextColor ( c ) ;
2018-02-08 12:02:44 +01:00
loadingSpinner - > SetColor ( alphaMul ( c , 0.7f ) ) ;
2018-01-01 21:51:09 -08:00
} ) ;
2017-12-10 00:05:10 -08:00
loadingViewColor_ - > Persist ( ) ;
2018-01-01 21:51:09 -08:00
// We start invisible here, in case of recreated views.
2018-04-29 14:44:00 -07:00
loadingViewVisible_ = loadingSpinner - > AddTween ( new VisibilityTween ( UI : : V_INVISIBLE , UI : : V_INVISIBLE , 0.2f , & bezierEaseInOut ) ) ;
2017-12-10 00:05:10 -08:00
loadingViewVisible_ - > Persist ( ) ;
2018-04-29 14:44:00 -07:00
loadingViewVisible_ - > Finish . Add ( [ loadingBG , loadingSpinner ] ( EventParams & p ) {
2018-01-01 21:51:09 -08:00
loadingBG - > SetVisibility ( p . v - > GetVisibility ( ) ) ;
// If we just became invisible, flush BGs since we don't need them anymore.
// Saves some VRAM for the game, but don't do it before we fade out...
if ( p . v - > GetVisibility ( ) = = V_INVISIBLE ) {
g_gameInfoCache - > FlushBGs ( ) ;
2018-04-29 14:44:00 -07:00
// And we can go away too. This means the tween will never run again.
loadingBG - > SetVisibility ( V_GONE ) ;
loadingSpinner - > SetVisibility ( V_GONE ) ;
2018-01-01 21:51:09 -08:00
}
return EVENT_DONE ;
} ) ;
2023-03-26 14:32:30 -07:00
// Will become visible along with the loadingView.
loadingBG - > SetVisibility ( V_INVISIBLE ) ;
2013-09-07 20:54:11 +02:00
}
2024-11-05 11:18:26 +01:00
void EmuScreen : : deviceLost ( ) {
UIScreen : : deviceLost ( ) ;
if ( imguiInited_ ) {
ImGui_ImplThin3d_DestroyDeviceObjects ( ) ;
}
}
void EmuScreen : : deviceRestored ( Draw : : DrawContext * draw ) {
UIScreen : : deviceRestored ( draw ) ;
if ( imguiInited_ ) {
ImGui_ImplThin3d_CreateDeviceObjects ( draw ) ;
}
}
2013-09-07 20:54:11 +02:00
UI : : EventReturn EmuScreen : : OnDevTools ( UI : : EventParams & params ) {
2023-04-06 00:34:50 +02:00
DevMenuScreen * devMenu = new DevMenuScreen ( gamePath_ , I18NCat : : DEVELOPER ) ;
2017-03-21 18:27:57 -07:00
if ( params . v )
devMenu - > SetPopupOrigin ( params . v ) ;
screenManager ( ) - > push ( devMenu ) ;
2013-09-07 20:54:11 +02:00
return UI : : EVENT_DONE ;
2013-07-20 12:06:06 +02:00
}
2019-10-25 10:56:01 +02:00
UI : : EventReturn EmuScreen : : OnDisableCardboard ( UI : : EventParams & params ) {
2019-10-25 11:01:49 +02:00
g_Config . bEnableCardboardVR = false ;
2019-10-25 10:56:01 +02:00
return UI : : EVENT_DONE ;
}
2020-12-19 20:26:02 +01:00
UI : : EventReturn EmuScreen : : OnChat ( UI : : EventParams & params ) {
2021-02-15 20:37:24 -08:00
if ( chatButton_ ! = nullptr & & chatButton_ - > GetVisibility ( ) = = UI : : V_VISIBLE ) {
chatButton_ - > SetVisibility ( UI : : V_GONE ) ;
2020-12-19 20:26:02 +01:00
}
2021-09-12 19:44:44 -07:00
if ( chatMenu_ ! = nullptr ) {
chatMenu_ - > SetVisibility ( UI : : V_VISIBLE ) ;
# if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(SDL)
UI : : EnableFocusMovement ( true ) ;
root_ - > SetDefaultFocusView ( chatMenu_ ) ;
2021-09-12 20:16:05 -07:00
2021-09-12 19:44:44 -07:00
chatMenu_ - > SetFocus ( ) ;
2021-09-12 20:16:05 -07:00
UI : : View * focused = UI : : GetFocusedView ( ) ;
if ( focused ) {
root_ - > SubviewFocused ( focused ) ;
}
2021-09-12 19:44:44 -07:00
# endif
}
2016-10-21 18:35:54 +08:00
return UI : : EVENT_DONE ;
}
2020-12-19 20:26:02 +01:00
UI : : EventReturn EmuScreen : : OnResume ( UI : : EventParams & params ) {
if ( coreState = = CoreState : : CORE_RUNTIME_ERROR ) {
// Force it!
Memory : : MemFault_IgnoreLastCrash ( ) ;
coreState = CoreState : : CORE_RUNNING ;
}
return UI : : EVENT_DONE ;
}
2024-11-04 01:05:36 +01:00
// To avoid including proAdhoc.h, which includes a lot of stuff.
int GetChatMessageCount ( ) ;
2017-03-14 22:01:18 -07:00
void EmuScreen : : update ( ) {
2020-12-19 20:26:02 +01:00
using namespace UI ;
2017-12-03 11:56:42 -08:00
UIScreen : : update ( ) ;
2020-12-19 20:26:02 +01:00
resumeButton_ - > SetVisibility ( coreState = = CoreState : : CORE_RUNTIME_ERROR & & Memory : : MemFault_MayBeResumable ( ) ? V_VISIBLE : V_GONE ) ;
2021-08-08 23:03:19 -07:00
resetButton_ - > SetVisibility ( coreState = = CoreState : : CORE_RUNTIME_ERROR ? V_VISIBLE : V_GONE ) ;
2024-10-03 18:55:22 +02:00
backButton_ - > SetVisibility ( coreState = = CoreState : : CORE_RUNTIME_ERROR ? V_VISIBLE : V_GONE ) ;
2017-12-03 11:56:42 -08:00
2021-09-14 17:59:46 -07:00
if ( chatButton_ & & chatMenu_ ) {
if ( chatMenu_ - > GetVisibility ( ) ! = V_GONE ) {
chatMessages_ = GetChatMessageCount ( ) ;
newChatMessages_ = 0 ;
} else {
int diff = GetChatMessageCount ( ) - chatMessages_ ;
// Cap the count at 50.
newChatMessages_ = diff > 50 ? 50 : diff ;
}
}
2020-11-22 19:08:14 +01:00
if ( bootPending_ ) {
2023-07-24 12:00:16 +02:00
// Keep trying the boot until bootPending_ is lifted.
// It may be delayed due to RetroAchievements or any other cause.
2013-07-27 13:26:26 +02:00
bootGame ( gamePath_ ) ;
2020-11-22 19:08:14 +01:00
}
2013-07-27 13:26:26 +02:00
2016-03-20 09:52:13 +01:00
// Simply forcibly update to the current screen size every frame. Doesn't cost much.
2014-02-10 15:14:45 +01:00
// If bounds is set to be smaller than the actual pixel resolution of the display, respect that.
// TODO: Should be able to use g_dpi_scale here instead. Might want to store the dpi scale in the UI context too.
2017-03-06 13:50:22 +01:00
# ifndef _WIN32
2014-02-10 15:14:45 +01:00
const Bounds & bounds = screenManager ( ) - > getUIContext ( ) - > GetBounds ( ) ;
2023-02-25 13:09:44 +01:00
PSP_CoreParameter ( ) . pixelWidth = g_display . pixel_xres * bounds . w / g_display . dp_xres ;
PSP_CoreParameter ( ) . pixelHeight = g_display . pixel_yres * bounds . h / g_display . dp_yres ;
2017-03-06 13:50:22 +01:00
# endif
2013-07-16 22:50:53 +02:00
2021-08-08 23:40:41 -07:00
if ( ! invalid_ ) {
UpdateUIState ( coreState ! = CORE_RUNTIME_ERROR ? UISTATE_INGAME : UISTATE_EXCEPTION ) ;
2014-05-21 01:13:40 -07:00
}
2013-11-15 13:11:44 +01:00
2012-11-01 16:19:01 +01:00
if ( errorMessage_ . size ( ) ) {
2023-04-06 00:34:50 +02:00
auto err = GetI18NCategory ( I18NCat : : ERRORS ) ;
2021-05-11 09:50:28 +02:00
std : : string errLoadingFile = gamePath_ . ToVisualString ( ) + " \n " ;
2019-03-13 11:24:23 +01:00
errLoadingFile . append ( err - > T ( " Error loading file " , " Could not load game " ) ) ;
2013-08-22 15:37:49 -04:00
errLoadingFile . append ( " " ) ;
2015-07-01 23:34:50 +02:00
errLoadingFile . append ( err - > T ( errorMessage_ . c_str ( ) ) ) ;
2013-08-22 15:37:49 -04:00
2022-11-29 16:29:43 +01:00
screenManager ( ) - > push ( new PromptScreen ( gamePath_ , errLoadingFile , " OK " , " " ) ) ;
2022-09-30 12:26:30 +03:00
errorMessage_ . clear ( ) ;
2014-01-25 00:40:14 -08:00
quit_ = true ;
2012-11-01 16:19:01 +01:00
return ;
}
2024-10-03 18:38:54 +02:00
if ( pauseTrigger_ ) {
pauseTrigger_ = false ;
screenManager ( ) - > push ( new GamePauseScreen ( gamePath_ ) ) ;
}
2012-11-01 16:19:01 +01:00
if ( invalid_ )
return ;
2012-12-26 08:51:03 +01:00
2023-08-23 18:42:20 +02:00
double now = time_now_d ( ) ;
controlMapper_ . Update ( now ) ;
2020-03-23 00:45:22 +01:00
2016-08-16 21:24:01 -07:00
if ( saveStatePreview_ & & ! bootPending_ ) {
2016-05-27 20:41:37 -07:00
int currentSlot = SaveState : : GetCurrentSlot ( ) ;
if ( saveStateSlot_ ! = currentSlot ) {
saveStateSlot_ = currentSlot ;
2021-05-06 01:31:38 +02:00
Path fn ;
2021-05-14 23:00:22 -07:00
if ( SaveState : : HasSaveInSlot ( gamePath_ , currentSlot ) ) {
fn = SaveState : : GenerateSaveSlotFilename ( gamePath_ , currentSlot , SaveState : : SCREENSHOT_EXTENSION ) ;
2016-05-27 20:41:37 -07:00
}
saveStatePreview_ - > SetFilename ( fn ) ;
if ( ! fn . empty ( ) ) {
saveStatePreview_ - > SetVisibility ( UI : : V_VISIBLE ) ;
2023-08-23 18:42:20 +02:00
saveStatePreviewShownTime_ = now ;
2016-05-27 20:41:37 -07:00
} else {
saveStatePreview_ - > SetVisibility ( UI : : V_GONE ) ;
}
}
2016-05-27 20:53:58 -07:00
if ( saveStatePreview_ - > GetVisibility ( ) = = UI : : V_VISIBLE ) {
double endTime = saveStatePreviewShownTime_ + 2.0 ;
2023-08-23 18:42:20 +02:00
float alpha = clamp_value ( ( endTime - now ) * 4.0 , 0.0 , 1.0 ) ;
2016-05-27 20:53:58 -07:00
saveStatePreview_ - > SetColor ( colorAlpha ( 0x00FFFFFF , alpha ) ) ;
2023-08-23 18:42:20 +02:00
if ( now - saveStatePreviewShownTime_ > 2 ) {
2016-05-27 20:53:58 -07:00
saveStatePreview_ - > SetVisibility ( UI : : V_GONE ) ;
}
2016-05-27 20:41:37 -07:00
}
2015-02-01 18:04:06 +01:00
}
2012-11-01 16:19:01 +01:00
}
2023-10-11 09:04:28 +02:00
bool EmuScreen : : checkPowerDown ( ) {
2022-10-02 07:25:15 -07:00
if ( PSP_IsRebooting ( ) ) {
bootPending_ = true ;
invalid_ = true ;
}
2022-10-01 18:13:22 -07:00
if ( coreState = = CORE_POWERDOWN & & ! PSP_IsIniting ( ) & & ! PSP_IsRebooting ( ) ) {
2024-10-22 11:59:41 +02:00
bool shutdown = false ;
2014-05-21 01:13:40 -07:00
if ( PSP_IsInited ( ) ) {
PSP_Shutdown ( ) ;
2024-10-22 11:59:41 +02:00
shutdown = true ;
2014-05-21 01:13:40 -07:00
}
2024-07-14 14:42:59 +02:00
INFO_LOG ( Log : : System , " SELF-POWERDOWN! " ) ;
2014-05-21 01:13:40 -07:00
screenManager ( ) - > switchScreen ( new MainScreen ( ) ) ;
bootPending_ = false ;
invalid_ = true ;
2024-10-22 11:59:41 +02:00
return shutdown ;
2014-05-21 01:13:40 -07:00
}
2023-10-11 09:04:28 +02:00
return false ;
2014-05-21 01:13:40 -07:00
}
2024-05-11 21:28:26 +02:00
ScreenRenderRole EmuScreen : : renderRole ( bool isTop ) const {
auto CanBeBackground = [ & ] ( ) - > bool {
if ( g_Config . bSkipBufferEffects ) {
return isTop | | ( g_Config . bTransparentBackground & & Core_ShouldRunBehind ( ) ) ;
}
2023-12-10 21:57:05 +01:00
2024-05-11 21:28:26 +02:00
if ( ! g_Config . bTransparentBackground & & ! isTop ) {
if ( Core_ShouldRunBehind ( ) | | screenManager ( ) - > topScreen ( ) - > wantBrightBackground ( ) )
return true ;
return false ;
}
2024-10-03 18:38:54 +02:00
if ( invalid_ ) {
return false ;
}
2024-05-11 21:28:26 +02:00
return true ;
} ;
ScreenRenderRole role = ScreenRenderRole : : MUST_BE_FIRST ;
if ( CanBeBackground ( ) ) {
role | = ScreenRenderRole : : CAN_BE_BACKGROUND ;
2023-12-11 17:47:19 +01:00
}
2024-05-11 21:28:26 +02:00
return role ;
2023-12-10 21:57:05 +01:00
}
void EmuScreen : : darken ( ) {
if ( ! screenManager ( ) - > topScreen ( ) - > wantBrightBackground ( ) ) {
UIContext & dc = * screenManager ( ) - > getUIContext ( ) ;
uint32_t color = GetBackgroundColorWithAlpha ( dc ) ;
dc . Begin ( ) ;
dc . RebindTexture ( ) ;
dc . FillRect ( UI : : Drawable ( color ) , dc . GetBounds ( ) ) ;
dc . Flush ( ) ;
}
}
2023-12-11 12:41:44 +01:00
ScreenRenderFlags EmuScreen : : render ( ScreenRenderMode mode ) {
ScreenRenderFlags flags = ScreenRenderFlags : : NONE ;
2023-12-15 11:30:54 +01:00
Draw : : Viewport viewport { 0.0f , 0.0f , ( float ) g_display . pixel_xres , ( float ) g_display . pixel_yres , 0.0f , 1.0f } ;
2023-12-11 12:41:44 +01:00
using namespace Draw ;
DrawContext * draw = screenManager ( ) - > getDrawContext ( ) ;
2023-12-29 00:17:35 +01:00
if ( ! draw ) {
2023-12-11 12:41:44 +01:00
return flags ; // shouldn't really happen but I've seen a suspicious stack trace..
2023-12-29 00:17:35 +01:00
}
2023-12-11 12:41:44 +01:00
2023-12-29 17:07:49 +01:00
GamepadUpdateOpacity ( ) ;
2023-12-11 15:58:08 +01:00
bool skipBufferEffects = g_Config . bSkipBufferEffects ;
2024-01-24 00:06:01 +01:00
bool framebufferBound = false ;
2023-12-10 21:57:05 +01:00
if ( mode & ScreenRenderMode : : FIRST ) {
// Actually, always gonna be first when it exists (?)
2023-12-10 14:09:55 +01:00
// Here we do NOT bind the backbuffer or clear the screen, unless non-buffered.
// The emuscreen is different than the others - we really want to allow the game to render to framebuffers
// before we ever bind the backbuffer for rendering. On mobile GPUs, switching back and forth between render
// targets is a mortal sin so it's very important that we don't bind the backbuffer unnecessarily here.
// We only bind it in FramebufferManager::CopyDisplayToOutput (unless non-buffered)...
// We do, however, start the frame in other ways.
2024-05-29 14:47:50 +02:00
if ( skipBufferEffects & & ! g_Config . bSoftwareRendering ) {
2023-12-10 14:09:55 +01:00
// We need to clear here already so that drawing during the frame is done on a clean slate.
if ( Core_IsStepping ( ) & & gpuStats . numFlips ! = 0 ) {
2024-01-18 09:44:40 +01:00
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : KEEP , RPAction : : CLEAR , RPAction : : CLEAR } , " EmuScreen_BackBuffer " ) ;
2023-12-10 14:09:55 +01:00
} else {
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , 0xFF000000 } , " EmuScreen_BackBuffer " ) ;
}
2017-05-16 14:24:40 +02:00
2023-12-10 14:09:55 +01:00
draw - > SetViewport ( viewport ) ;
2023-12-15 11:30:54 +01:00
draw - > SetScissorRect ( 0 , 0 , g_display . pixel_xres , g_display . pixel_yres ) ;
2024-01-24 00:06:01 +01:00
framebufferBound = true ;
2023-12-10 14:09:55 +01:00
}
draw - > SetTargetSize ( g_display . pixel_xres , g_display . pixel_yres ) ;
2024-10-17 21:43:03 +02:00
} else {
// Some other screen bound the backbuffer first.
framebufferBound = true ;
2017-05-16 14:24:40 +02:00
}
2023-07-16 08:55:48 +02:00
g_OSD . NudgeSidebar ( ) ;
2023-12-10 21:57:05 +01:00
if ( mode & ScreenRenderMode : : TOP ) {
2023-08-10 13:21:36 +02:00
System_Notify ( SystemNotification : : KEEP_SCREEN_AWAKE ) ;
2023-12-30 15:18:56 +01:00
} else if ( ! Core_ShouldRunBehind ( ) & & strcmp ( screenManager ( ) - > topScreen ( ) - > tag ( ) , " DevMenu " ) ! = 0 ) {
2024-10-17 21:43:03 +02:00
// NOTE: The strcmp is != 0 - so all popped-over screens EXCEPT DevMenu
2023-12-10 21:57:05 +01:00
// Just to make sure.
2024-02-01 23:26:36 +01:00
if ( PSP_IsInited ( ) & & ! skipBufferEffects ) {
2024-02-03 00:20:08 +01:00
_dbg_assert_ ( gpu ) ;
2023-12-10 21:57:05 +01:00
PSP_BeginHostFrame ( ) ;
gpu - > CopyDisplayToOutput ( true ) ;
PSP_EndHostFrame ( ) ;
2024-02-01 19:58:49 +01:00
}
2024-10-17 22:21:25 +02:00
if ( gpu - > PresentedThisFrame ( ) ) {
framebufferBound = true ;
}
2024-10-17 21:43:03 +02:00
if ( ! framebufferBound ) {
2024-02-01 19:58:49 +01:00
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , } , " EmuScreen_Behind " ) ;
2023-12-10 21:57:05 +01:00
}
2024-10-25 12:00:28 +02:00
Draw : : BackendState state = draw - > GetCurrentBackendState ( ) ;
2024-10-28 12:43:18 +01:00
if ( state . valid ) {
2024-11-01 20:27:09 +01:00
_dbg_assert_msg_ ( state . passes > = 1 , " skipB: %d sw: %d mode: %d back: %d tag: %s behi: %d " , ( int ) skipBufferEffects , ( int ) g_Config . bSoftwareRendering , ( int ) mode , ( int ) g_Config . iGPUBackend , screenManager ( ) - > topScreen ( ) - > tag ( ) , ( int ) g_Config . bRunBehindPauseMenu ) ;
2024-10-31 23:09:47 +01:00
// Workaround any remaining bugs like this.
if ( state . passes = = 0 ) {
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , } , " EmuScreen_SafeFallback " ) ;
}
2024-10-28 12:43:18 +01:00
}
2024-10-25 12:00:28 +02:00
2024-01-18 18:46:52 +01:00
// Need to make sure the UI texture is available, for "darken".
screenManager ( ) - > getUIContext ( ) - > BeginFrame ( ) ;
2023-12-29 00:17:35 +01:00
draw - > SetViewport ( viewport ) ;
draw - > SetScissorRect ( 0 , 0 , g_display . pixel_xres , g_display . pixel_yres ) ;
darken ( ) ;
2023-12-11 12:41:44 +01:00
return flags ;
2023-08-10 13:21:36 +02:00
}
2014-05-21 01:13:40 -07:00
if ( invalid_ ) {
2018-03-13 11:25:00 +01:00
// Loading, or after shutdown?
2024-01-14 23:27:40 +01:00
if ( loadingTextView_ & & loadingTextView_ - > GetVisibility ( ) = = UI : : V_VISIBLE )
2018-03-13 11:25:00 +01:00
loadingTextView_ - > SetText ( PSP_GetLoading ( ) ) ;
2014-05-21 01:13:40 -07:00
// It's possible this might be set outside PSP_RunLoopFor().
// In this case, we need to double check it here.
2023-12-30 11:58:29 +01:00
if ( mode & ScreenRenderMode : : TOP ) {
checkPowerDown ( ) ;
}
2023-12-11 12:41:44 +01:00
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR } , " EmuScreen_Invalid " ) ;
2024-01-18 18:46:52 +01:00
// Need to make sure the UI texture is available, for "darken".
screenManager ( ) - > getUIContext ( ) - > BeginFrame ( ) ;
2023-12-15 11:30:54 +01:00
draw - > SetViewport ( viewport ) ;
draw - > SetScissorRect ( 0 , 0 , g_display . pixel_xres , g_display . pixel_yres ) ;
2017-12-03 10:39:25 -08:00
renderUI ( ) ;
2023-12-11 12:41:44 +01:00
return flags ;
2014-05-21 01:13:40 -07:00
}
2012-11-01 16:19:01 +01:00
2020-08-02 17:11:09 +02:00
// Freeze-frame functionality (loads a savestate on every frame).
2013-11-15 13:11:44 +01:00
if ( PSP_CoreParameter ( ) . freezeNext ) {
PSP_CoreParameter ( ) . frozen = true ;
PSP_CoreParameter ( ) . freezeNext = false ;
SaveState : : SaveToRam ( freezeState_ ) ;
} else if ( PSP_CoreParameter ( ) . frozen ) {
2020-08-02 17:11:09 +02:00
std : : string errorString ;
if ( CChunkFileReader : : ERROR_NONE ! = SaveState : : LoadFromRam ( freezeState_ , & errorString ) ) {
2024-07-14 14:42:59 +02:00
ERROR_LOG ( Log : : SaveState , " Failed to load freeze state (%s). Unfreezing. " , errorString . c_str ( ) ) ;
2013-11-15 13:11:44 +01:00
PSP_CoreParameter ( ) . frozen = false ;
}
}
2023-08-03 16:19:18 +02:00
Core_UpdateDebugStats ( ( DebugOverlay ) g_Config . iDebugOverlay = = DebugOverlay : : DEBUG_STATS | | g_Config . bLogFrameDrops ) ;
2017-11-08 11:57:53 +01:00
2024-09-18 15:17:20 +02:00
if ( doFrameAdvance_ . exchange ( false ) ) {
if ( ! Achievements : : WarnUserIfHardcoreModeActive ( false ) ) {
// If game is running, pause emulation immediately. Otherwise, advance a single frame.
if ( Core_IsStepping ( ) ) {
frameStep_ = true ;
2024-11-01 22:52:47 +01:00
Core_Resume ( ) ;
2024-09-18 15:17:20 +02:00
} else if ( ! frameStep_ ) {
lastNumFlips = gpuStats . numFlips ;
2024-11-01 22:52:47 +01:00
Core_Break ( " ui.frameAdvance " , 0 ) ;
2024-09-18 15:17:20 +02:00
}
}
}
2023-07-03 09:18:25 +02:00
bool blockedExecution = Achievements : : IsBlockingExecution ( ) ;
2023-12-20 17:03:06 +01:00
uint32_t clearColor = 0 ;
2023-07-03 09:18:25 +02:00
if ( ! blockedExecution ) {
PSP_BeginHostFrame ( ) ;
2024-10-17 21:09:04 +02:00
if ( SaveState : : Process ( ) ) {
// We might have lost the framebuffer bind if we had one, due to a readback.
if ( framebufferBound ) {
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , clearColor } , " EmuScreen_SavestateRebind " ) ;
}
}
2023-07-03 09:18:25 +02:00
PSP_RunLoopWhileState ( ) ;
2024-11-21 14:36:31 +01:00
// Hopefully, after running, coreState is now CORE_NEXTFRAME
2023-07-03 09:18:25 +02:00
switch ( coreState ) {
case CORE_NEXTFRAME :
// Reached the end of the frame, all good. Set back to running for the next frame
coreState = CORE_RUNNING ;
2024-11-15 17:37:23 +01:00
flags | = ScreenRenderFlags : : HANDLED_THROTTLING ;
2023-07-03 09:18:25 +02:00
break ;
case CORE_STEPPING :
case CORE_RUNTIME_ERROR :
{
// If there's an exception, display information.
const MIPSExceptionInfo & info = Core_GetExceptionInfo ( ) ;
if ( info . type ! = MIPSExceptionType : : NONE ) {
// Clear to blue background screen
bool dangerousSettings = ! Reporting : : IsSupported ( ) ;
2023-12-20 17:03:06 +01:00
clearColor = dangerousSettings ? 0xFF900050 : 0xFF900000 ;
2024-01-18 09:44:40 +01:00
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , clearColor } , " EmuScreen_RuntimeError " ) ;
2024-01-24 00:06:01 +01:00
framebufferBound = true ;
2023-07-03 09:18:25 +02:00
// The info is drawn later in renderUI
} else {
// If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output.
// This won't work in non-buffered, but that's fine.
2024-05-29 14:47:50 +02:00
if ( ! framebufferBound & & PSP_IsInited ( ) ) {
// draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_Stepping");
2023-07-03 09:18:25 +02:00
gpu - > CopyDisplayToOutput ( true ) ;
2024-10-02 00:58:50 +02:00
framebufferBound = true ;
2023-07-03 09:18:25 +02:00
}
2020-07-04 20:57:05 +02:00
}
2023-07-03 09:18:25 +02:00
break ;
}
default :
// Didn't actually reach the end of the frame, ran out of the blockTicks cycles.
// In this case we need to bind and wipe the backbuffer, at least.
// It's possible we never ended up outputted anything - make sure we have the backbuffer cleared
2024-01-24 00:06:01 +01:00
// So, we don't set framebufferBound here.
2024-11-15 17:37:23 +01:00
// However, let's not cause a UI sleep in the mainloop.
flags | = ScreenRenderFlags : : HANDLED_THROTTLING ;
2023-07-03 09:18:25 +02:00
break ;
2018-06-23 10:58:30 -07:00
}
2020-07-04 20:57:05 +02:00
2023-07-03 09:18:25 +02:00
PSP_EndHostFrame ( ) ;
2024-01-22 19:35:26 +01:00
// This place rougly matches how libretro handles it (after retro_frame).
Achievements : : FrameUpdate ( ) ;
2023-07-03 09:18:25 +02:00
}
2012-11-01 16:19:01 +01:00
2024-02-02 13:55:38 +01:00
if ( gpu & & gpu - > PresentedThisFrame ( ) ) {
2024-01-24 00:06:01 +01:00
framebufferBound = true ;
}
2024-01-18 18:46:52 +01:00
2024-01-24 00:06:01 +01:00
if ( ! framebufferBound ) {
2023-12-20 17:03:06 +01:00
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , clearColor } , " EmuScreen_NoFrame " ) ;
2023-12-11 15:58:08 +01:00
draw - > SetViewport ( viewport ) ;
draw - > SetScissorRect ( 0 , 0 , g_display . pixel_xres , g_display . pixel_yres ) ;
2023-12-11 12:41:44 +01:00
}
2024-10-03 11:59:56 +02:00
Draw : : BackendState state = draw - > GetCurrentBackendState ( ) ;
2024-10-03 16:48:19 +02:00
2024-10-28 12:43:18 +01:00
// State.valid just states whether the passes parameter has a meaningful value.
if ( state . valid ) {
2024-10-31 23:09:47 +01:00
_dbg_assert_msg_ ( state . passes > = 1 , " skipB: %d sw: %d mode: %d back: %d bound: %d " , ( int ) skipBufferEffects , ( int ) g_Config . bSoftwareRendering , ( int ) mode , ( int ) g_Config . iGPUBackend , ( int ) framebufferBound ) ;
if ( state . passes = = 0 ) {
// Workaround any remaining bugs like this.
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , } , " EmuScreen_SafeFallback " ) ;
}
2024-10-28 12:43:18 +01:00
}
2024-10-03 11:59:56 +02:00
2024-01-18 22:08:33 +01:00
screenManager ( ) - > getUIContext ( ) - > BeginFrame ( ) ;
2023-12-11 12:41:44 +01:00
if ( ! ( mode & ScreenRenderMode : : TOP ) ) {
2024-11-21 14:36:31 +01:00
renderImDebugger ( ) ;
// We're in run-behind mode, but we don't want to draw chat, debug UI and stuff. We do draw the imdebugger though.
2023-12-11 12:41:44 +01:00
// So, darken and bail here.
2023-12-15 11:30:54 +01:00
// Reset viewport/scissor to be sure.
draw - > SetViewport ( viewport ) ;
draw - > SetScissorRect ( 0 , 0 , g_display . pixel_xres , g_display . pixel_yres ) ;
2023-12-11 12:41:44 +01:00
darken ( ) ;
return flags ;
2023-10-11 09:04:28 +02:00
}
2017-11-11 18:31:13 -08:00
2023-12-30 11:58:29 +01:00
// NOTE: We don't check for powerdown if we're not the top screen.
2024-10-22 11:59:41 +02:00
if ( checkPowerDown ( ) ) {
draw - > BindFramebufferAsRenderTarget ( nullptr , { RPAction : : CLEAR , RPAction : : CLEAR , RPAction : : CLEAR , clearColor } , " EmuScreen_PowerDown " ) ;
}
2023-12-30 11:58:29 +01:00
2018-12-18 10:23:22 +01:00
if ( hasVisibleUI ( ) ) {
2023-12-15 11:30:54 +01:00
draw - > SetViewport ( viewport ) ;
2019-10-25 11:01:49 +02:00
cardboardDisableButton_ - > SetVisibility ( g_Config . bEnableCardboardVR ? UI : : V_VISIBLE : UI : : V_GONE ) ;
2018-12-18 10:23:22 +01:00
screenManager ( ) - > getUIContext ( ) - > BeginFrame ( ) ;
2017-12-03 10:39:25 -08:00
renderUI ( ) ;
2014-12-31 16:50:23 +01:00
}
2022-11-17 12:19:17 +01:00
2022-11-17 15:25:35 +01:00
if ( chatMenu_ & & ( chatMenu_ - > GetVisibility ( ) = = UI : : V_VISIBLE ) ) {
SetVRAppMode ( VRAppMode : : VR_DIALOG_MODE ) ;
} else {
SetVRAppMode ( screenManager ( ) - > topScreen ( ) = = this ? VRAppMode : : VR_GAME_MODE : VRAppMode : : VR_DIALOG_MODE ) ;
}
2023-12-10 14:09:55 +01:00
2024-11-21 14:36:31 +01:00
renderImDebugger ( ) ;
return flags ;
}
void EmuScreen : : renderImDebugger ( ) {
2024-11-12 12:20:14 +01:00
if ( g_Config . bShowImDebugger ) {
2024-11-21 14:36:31 +01:00
Draw : : DrawContext * draw = screenManager ( ) - > getDrawContext ( ) ;
2024-11-12 12:20:14 +01:00
if ( ! imguiInited_ ) {
imguiInited_ = true ;
imDebugger_ = std : : make_unique < ImDebugger > ( ) ;
ImGui_ImplThin3d_Init ( draw ) ;
}
2024-10-30 08:07:59 +01:00
2024-11-12 12:20:14 +01:00
if ( PSP_IsInited ( ) ) {
_dbg_assert_ ( imDebugger_ ) ;
2024-11-04 01:05:36 +01:00
2024-11-12 12:20:14 +01:00
ImGui_ImplPlatform_NewFrame ( ) ;
ImGui_ImplThin3d_NewFrame ( draw , ui_draw2d . GetDrawMatrix ( ) ) ;
2024-10-30 08:07:59 +01:00
2024-11-12 12:20:14 +01:00
ImGui : : NewFrame ( ) ;
imDebugger_ - > Frame ( currentDebugMIPS ) ;
2024-10-30 08:07:59 +01:00
2024-11-12 12:20:14 +01:00
ImGui : : Render ( ) ;
ImGui_ImplThin3d_RenderDrawData ( ImGui : : GetDrawData ( ) , draw ) ;
}
2024-10-30 23:59:57 +01:00
}
2012-11-01 16:19:01 +01:00
}
2018-06-01 21:07:09 -07:00
bool EmuScreen : : hasVisibleUI ( ) {
// Regular but uncommon UI.
if ( saveStatePreview_ - > GetVisibility ( ) ! = UI : : V_GONE | | loadingSpinner_ - > GetVisibility ( ) = = UI : : V_VISIBLE )
return true ;
2023-06-20 14:40:46 +02:00
if ( ! g_OSD . IsEmpty ( ) | | g_Config . bShowTouchControls | | g_Config . iShowStatusFlags ! = 0 )
2018-06-01 21:07:09 -07:00
return true ;
2021-02-15 20:38:11 -08:00
if ( g_Config . bEnableCardboardVR | | g_Config . bEnableNetworkChat )
2019-10-25 10:56:01 +02:00
return true ;
2024-05-12 18:01:25 +02:00
if ( g_Config . bShowGPOLEDs )
return true ;
2018-06-01 21:07:09 -07:00
// Debug UI.
2023-08-11 15:51:54 +02:00
if ( ( DebugOverlay ) g_Config . iDebugOverlay ! = DebugOverlay : : OFF | | g_Config . bShowDeveloperMenu )
2018-06-01 21:07:09 -07:00
return true ;
2019-02-12 13:29:37 +01:00
// Exception information.
2019-02-12 13:29:37 +01:00
if ( coreState = = CORE_RUNTIME_ERROR | | coreState = = CORE_STEPPING ) {
2019-02-12 13:29:37 +01:00
return true ;
2019-02-12 13:29:37 +01:00
}
2018-06-01 21:07:09 -07:00
return false ;
}
2017-12-03 10:39:25 -08:00
void EmuScreen : : renderUI ( ) {
using namespace Draw ;
DrawContext * thin3d = screenManager ( ) - > getDrawContext ( ) ;
2018-01-17 13:59:32 +01:00
UIContext * ctx = screenManager ( ) - > getUIContext ( ) ;
2018-03-08 16:34:27 +01:00
ctx - > BeginFrame ( ) ;
2017-12-03 10:39:25 -08:00
// This sets up some important states but not the viewport.
2018-01-17 13:59:32 +01:00
ctx - > Begin ( ) ;
2017-12-03 10:39:25 -08:00
Viewport viewport ;
viewport . TopLeftX = 0 ;
viewport . TopLeftY = 0 ;
2023-02-25 13:09:44 +01:00
viewport . Width = g_display . pixel_xres ;
viewport . Height = g_display . pixel_yres ;
2017-12-03 10:39:25 -08:00
viewport . MaxDepth = 1.0 ;
viewport . MinDepth = 0.0 ;
2023-02-24 22:09:32 +01:00
thin3d - > SetViewport ( viewport ) ;
2017-12-03 10:39:25 -08:00
if ( root_ ) {
2020-05-31 23:20:13 +02:00
UI : : LayoutViewHierarchy ( * ctx , root_ , false ) ;
2018-01-17 13:59:32 +01:00
root_ - > Draw ( * ctx ) ;
2017-12-03 10:39:25 -08:00
}
2023-03-31 20:12:48 +02:00
if ( ! invalid_ ) {
2023-08-03 16:19:18 +02:00
if ( ( DebugOverlay ) g_Config . iDebugOverlay = = DebugOverlay : : CONTROL ) {
DrawControlMapperOverlay ( ctx , ctx - > GetLayoutBounds ( ) , controlMapper_ ) ;
}
2023-03-31 20:12:48 +02:00
if ( g_Config . iShowStatusFlags ) {
DrawFPS ( ctx , ctx - > GetLayoutBounds ( ) ) ;
}
2020-02-11 08:19:30 +01:00
}
2017-12-03 10:39:25 -08:00
# ifdef USE_PROFILER
2023-08-13 09:30:27 -07:00
if ( ( DebugOverlay ) g_Config . iDebugOverlay = = DebugOverlay : : FRAME_PROFILE & & ! invalid_ ) {
2018-01-17 13:59:32 +01:00
DrawProfile ( * ctx ) ;
2017-12-03 10:39:25 -08:00
}
# endif
2019-02-12 13:29:37 +01:00
2024-05-12 18:01:25 +02:00
if ( g_Config . bShowGPOLEDs ) {
// Draw a vertical strip of LEDs at the right side of the screen.
const float ledSize = 24.0f ;
const float spacing = 4.0f ;
const float height = 8 * ledSize + 7 * spacing ;
const float x = ctx - > GetBounds ( ) . w - spacing - ledSize ;
const float y = ( ctx - > GetBounds ( ) . h - height ) * 0.5f ;
ctx - > FillRect ( UI : : Drawable ( 0xFF000000 ) , Bounds ( x - spacing , y - spacing , ledSize + spacing * 2 , height + spacing * 2 ) ) ;
for ( int i = 0 ; i < 8 ; i + + ) {
int bit = ( g_GPOBits > > i ) & 1 ;
uint32_t color = 0xFF30FF30 ;
if ( ! bit ) {
color = darkenColor ( darkenColor ( color ) ) ;
}
Bounds ledBounds ( x , y + ( spacing + ledSize ) * i , ledSize , ledSize ) ;
ctx - > FillRect ( UI : : Drawable ( color ) , ledBounds ) ;
}
ctx - > Flush ( ) ;
}
2019-02-12 13:29:37 +01:00
if ( coreState = = CORE_RUNTIME_ERROR | | coreState = = CORE_STEPPING ) {
2023-04-28 13:38:16 +02:00
const MIPSExceptionInfo & info = Core_GetExceptionInfo ( ) ;
if ( info . type ! = MIPSExceptionType : : NONE ) {
2023-01-25 00:43:17 +01:00
DrawCrashDump ( ctx , gamePath_ ) ;
2022-12-30 12:21:05 +01:00
} else {
// We're somehow in ERROR or STEPPING without a crash dump. This case is what lead
// to the bare "Resume" and "Reset" buttons without a crash dump before, in cases
// where we were unable to ignore memory errors.
2019-02-12 13:29:37 +01:00
}
}
2018-12-18 10:10:53 +01:00
ctx - > Flush ( ) ;
2017-12-03 10:39:25 -08:00
}
2013-10-30 23:24:41 +05:30
void EmuScreen : : autoLoad ( ) {
2018-06-21 09:00:57 +01:00
int autoSlot = - 1 ;
2013-10-30 22:46:27 +05:30
//check if save state has save, if so, load
2018-06-21 09:00:57 +01:00
switch ( g_Config . iAutoLoadSaveState ) {
2018-06-26 07:52:02 +01:00
case ( int ) AutoLoadSaveState : : OFF : // "AutoLoad Off"
2018-06-21 09:00:57 +01:00
return ;
2018-06-26 07:52:02 +01:00
case ( int ) AutoLoadSaveState : : OLDEST : // "Oldest Save"
2021-05-14 23:00:22 -07:00
autoSlot = SaveState : : GetOldestSlot ( gamePath_ ) ;
2018-06-21 09:00:57 +01:00
break ;
2018-06-26 07:52:02 +01:00
case ( int ) AutoLoadSaveState : : NEWEST : // "Newest Save"
2021-05-14 23:00:22 -07:00
autoSlot = SaveState : : GetNewestSlot ( gamePath_ ) ;
2018-06-21 09:00:57 +01:00
break ;
default : // try the specific save state slot specified
2021-05-14 23:00:22 -07:00
autoSlot = ( SaveState : : HasSaveInSlot ( gamePath_ , g_Config . iAutoLoadSaveState - 3 ) ) ? ( g_Config . iAutoLoadSaveState - 3 ) : - 1 ;
2018-06-21 09:00:57 +01:00
break ;
}
if ( g_Config . iAutoLoadSaveState & & autoSlot ! = - 1 ) {
2021-05-14 23:00:22 -07:00
SaveState : : LoadSlot ( gamePath_ , autoSlot , & AfterSaveStateAction ) ;
2018-06-21 09:00:57 +01:00
g_Config . iCurrentStateSlot = autoSlot ;
2013-10-30 22:46:27 +05:30
}
2013-12-15 12:49:13 +01:00
}
2015-05-21 10:49:47 +02:00
2017-02-23 09:25:33 +01:00
void EmuScreen : : resized ( ) {
RecreateViews ( ) ;
2017-03-14 20:52:30 -07:00
}