2012-11-01 15:19:01 +00: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 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00: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 19:50:27 +00:00
|
|
|
#include "ppsspp_config.h"
|
|
|
|
|
2014-12-22 02:50:07 +00:00
|
|
|
#include <algorithm>
|
2015-02-01 17:04:06 +00:00
|
|
|
|
2014-02-10 11:38:23 +00:00
|
|
|
#include "base/display.h"
|
2013-03-06 23:10:53 +00:00
|
|
|
#include "base/logging.h"
|
2015-02-01 17:04:06 +00:00
|
|
|
#include "base/timeutil.h"
|
2015-05-13 21:07:19 +00:00
|
|
|
#include "profiler/profiler.h"
|
2013-03-06 23:10:53 +00:00
|
|
|
|
2015-09-06 10:23:14 +00:00
|
|
|
#include "gfx_es2/gpu_features.h"
|
2013-08-30 12:47:28 +00:00
|
|
|
#include "gfx_es2/draw_text.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
#include "input/input_state.h"
|
|
|
|
#include "ui/ui.h"
|
2013-08-30 12:47:28 +00:00
|
|
|
#include "ui/ui_context.h"
|
2013-05-27 12:25:30 +00:00
|
|
|
#include "i18n/i18n.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-07-01 04:43:01 +00:00
|
|
|
#include "Common/KeyMap.h"
|
|
|
|
|
2016-09-02 00:09:56 +00:00
|
|
|
#ifndef MOBILE_DEVICE
|
2016-08-27 18:38:05 +00:00
|
|
|
#include "Core/AVIDump.h"
|
2016-09-02 00:09:56 +00:00
|
|
|
#endif
|
2013-03-29 19:51:14 +00:00
|
|
|
#include "Core/Config.h"
|
|
|
|
#include "Core/CoreTiming.h"
|
|
|
|
#include "Core/CoreParameter.h"
|
|
|
|
#include "Core/Core.h"
|
|
|
|
#include "Core/Host.h"
|
2014-02-09 22:04:16 +00:00
|
|
|
#include "Core/Reporting.h"
|
2013-03-29 19:51:14 +00:00
|
|
|
#include "Core/System.h"
|
|
|
|
#include "GPU/GPUState.h"
|
|
|
|
#include "GPU/GPUInterface.h"
|
2017-01-21 21:16:30 +00:00
|
|
|
#include "GPU/GLES/FramebufferManagerGLES.h"
|
2013-03-29 19:51:14 +00:00
|
|
|
#include "Core/HLE/sceCtrl.h"
|
2013-04-07 20:43:23 +00:00
|
|
|
#include "Core/HLE/sceDisplay.h"
|
2015-10-28 20:20:20 +00:00
|
|
|
#include "Core/HLE/sceSas.h"
|
2013-03-29 19:51:14 +00:00
|
|
|
#include "Core/Debugger/SymbolMap.h"
|
2013-10-30 17:16:27 +00:00
|
|
|
#include "Core/SaveState.h"
|
2014-12-12 22:48:48 +00:00
|
|
|
#include "Core/MIPS/MIPS.h"
|
2015-01-29 11:55:49 +00:00
|
|
|
#include "Core/HLE/__sceAudio.h"
|
2016-10-21 10:35:54 +00:00
|
|
|
#include "Core/HLE/proAdhoc.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-04-07 20:43:23 +00:00
|
|
|
#include "UI/ui_atlas.h"
|
2016-09-04 15:42:20 +00:00
|
|
|
#include "UI/BackgroundAudio.h"
|
2013-12-05 13:14:15 +00:00
|
|
|
#include "UI/OnScreenDisplay.h"
|
2013-04-07 20:43:23 +00:00
|
|
|
#include "UI/GamepadEmu.h"
|
2014-12-22 09:48:17 +00:00
|
|
|
#include "UI/PauseScreen.h"
|
2013-06-10 20:06:51 +00:00
|
|
|
#include "UI/MainScreen.h"
|
2013-04-07 20:43:23 +00:00
|
|
|
#include "UI/EmuScreen.h"
|
2013-09-07 18:54:11 +00:00
|
|
|
#include "UI/DevScreens.h"
|
2013-04-13 19:24:07 +00:00
|
|
|
#include "UI/GameInfoCache.h"
|
2013-07-15 15:41:24 +00:00
|
|
|
#include "UI/MiscScreens.h"
|
2013-09-07 15:29:44 +00:00
|
|
|
#include "UI/ControlMappingScreen.h"
|
2015-12-21 05:32:05 +00:00
|
|
|
#include "UI/DisplayLayoutScreen.h"
|
2013-09-07 15:29:44 +00:00
|
|
|
#include "UI/GameSettingsScreen.h"
|
2013-12-05 13:14:15 +00:00
|
|
|
#include "UI/InstallZipScreen.h"
|
2015-10-14 15:45:21 +00:00
|
|
|
#include "UI/ProfilerDraw.h"
|
2016-10-21 10:35:54 +00:00
|
|
|
#include "UI/ChatScreen.h"
|
2013-07-17 05:33:26 +00:00
|
|
|
|
2017-02-24 19:50:27 +00:00
|
|
|
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
|
2016-03-20 19:26:52 +00:00
|
|
|
#include "Windows/MainWindow.h"
|
|
|
|
#endif
|
2017-02-24 19:50:27 +00:00
|
|
|
#if !PPSSPP_PLATFORM(UWP)
|
|
|
|
#include "gfx/gl_common.h"
|
|
|
|
#endif
|
2016-03-20 19:26:52 +00:00
|
|
|
|
2016-09-02 00:09:56 +00:00
|
|
|
#ifndef MOBILE_DEVICE
|
2016-08-27 18:38:05 +00:00
|
|
|
AVIDump avi;
|
2016-09-02 00:09:56 +00:00
|
|
|
#endif
|
2016-08-27 18:38:05 +00:00
|
|
|
|
2016-12-05 03:04:31 +00:00
|
|
|
UI::ChoiceWithValueDisplay *chatButtons;
|
|
|
|
|
2016-08-30 13:09:38 +00:00
|
|
|
static bool frameStep_;
|
|
|
|
static int lastNumFlips;
|
2016-08-27 18:38:05 +00:00
|
|
|
static bool startDumping;
|
2016-08-28 04:20:03 +00:00
|
|
|
static void __EmuScreenVblank()
|
|
|
|
{
|
2017-06-03 15:37:55 +00:00
|
|
|
I18NCategory *sy = GetI18NCategory("System");
|
|
|
|
|
2016-08-29 19:34:00 +00:00
|
|
|
if (frameStep_ && lastNumFlips != gpuStats.numFlips)
|
2016-08-28 04:20:03 +00:00
|
|
|
{
|
|
|
|
frameStep_ = false;
|
|
|
|
Core_EnableStepping(true);
|
2016-08-29 19:34:00 +00:00
|
|
|
lastNumFlips = gpuStats.numFlips;
|
2016-08-28 04:20:03 +00:00
|
|
|
}
|
2016-09-02 00:09:56 +00:00
|
|
|
#ifndef MOBILE_DEVICE
|
2016-08-27 18:38:05 +00:00
|
|
|
if (g_Config.bDumpFrames && !startDumping)
|
|
|
|
{
|
|
|
|
avi.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
|
2017-06-03 15:37:55 +00:00
|
|
|
osm.Show(sy->T("AVI Dump started."), 3.0f);
|
2016-08-27 18:38:05 +00:00
|
|
|
startDumping = true;
|
|
|
|
}
|
|
|
|
if (g_Config.bDumpFrames && startDumping)
|
|
|
|
{
|
|
|
|
avi.AddFrame();
|
|
|
|
}
|
|
|
|
else if (!g_Config.bDumpFrames && startDumping)
|
|
|
|
{
|
|
|
|
avi.Stop();
|
2017-06-03 15:37:55 +00:00
|
|
|
osm.Show(sy->T("AVI Dump stopped."), 3.0f);
|
2016-08-27 18:38:05 +00:00
|
|
|
startDumping = false;
|
|
|
|
}
|
2016-09-02 00:09:56 +00:00
|
|
|
#endif
|
2016-08-28 04:20:03 +00:00
|
|
|
}
|
|
|
|
|
2013-07-21 11:31:46 +00:00
|
|
|
EmuScreen::EmuScreen(const std::string &filename)
|
2015-02-01 17:04:06 +00:00
|
|
|
: bootPending_(true), gamePath_(filename), invalid_(true), quit_(false), pauseTrigger_(false), saveStatePreviewShownTime_(0.0), saveStatePreview_(nullptr) {
|
2014-07-20 10:52:11 +00:00
|
|
|
memset(axisState_, 0, sizeof(axisState_));
|
2016-05-28 03:41:37 +00:00
|
|
|
saveStateSlot_ = SaveState::GetCurrentSlot();
|
2016-08-28 04:20:03 +00:00
|
|
|
__DisplayListenVblank(__EmuScreenVblank);
|
2016-08-28 22:18:44 +00:00
|
|
|
frameStep_ = false;
|
2016-08-29 19:34:00 +00:00
|
|
|
lastNumFlips = gpuStats.numFlips;
|
2016-08-27 18:38:05 +00:00
|
|
|
startDumping = false;
|
2017-04-18 03:33:22 +00:00
|
|
|
|
|
|
|
OnDevMenu.Handle(this, &EmuScreen::OnDevTools);
|
2013-07-17 05:33:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmuScreen::bootGame(const std::string &filename) {
|
2014-01-19 22:17:34 +00:00
|
|
|
if (PSP_IsIniting()) {
|
|
|
|
std::string error_string;
|
2014-05-16 05:17:19 +00:00
|
|
|
bootPending_ = !PSP_InitUpdate(&error_string);
|
|
|
|
if (!bootPending_) {
|
2014-01-19 22:17:34 +00:00
|
|
|
invalid_ = !PSP_IsInited();
|
|
|
|
if (invalid_) {
|
|
|
|
errorMessage_ = error_string;
|
|
|
|
ERROR_LOG(BOOT, "%s", errorMessage_.c_str());
|
|
|
|
System_SendMessage("event", "failstartgame");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bootComplete();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-04 21:03:59 +00:00
|
|
|
SetBackgroundAudioGame("");
|
2016-09-04 15:42:20 +00:00
|
|
|
|
2014-12-14 19:33:20 +00:00
|
|
|
//pre-emptive loading of game specific config if possible, to get all the settings
|
2017-05-18 10:52:03 +00:00
|
|
|
std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(nullptr, filename, 0);
|
2015-11-13 00:14:56 +00:00
|
|
|
if (info && !info->id.empty()) {
|
2014-12-14 19:33:20 +00:00
|
|
|
g_Config.loadGameConfig(info->id);
|
|
|
|
}
|
|
|
|
|
2014-01-19 22:17:34 +00:00
|
|
|
invalid_ = true;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2017-03-06 12:50:22 +00:00
|
|
|
CoreParameter coreParam{};
|
2016-05-07 23:43:27 +00:00
|
|
|
coreParam.cpuCore = (CPUCore)g_Config.iCpuCore;
|
2016-04-10 08:21:48 +00:00
|
|
|
coreParam.gpuCore = GPUCORE_GLES;
|
2015-10-10 14:41:19 +00:00
|
|
|
switch (GetGPUBackend()) {
|
2017-02-24 19:50:27 +00:00
|
|
|
case GPUBackend::DIRECT3D11:
|
|
|
|
coreParam.gpuCore = GPUCORE_DIRECTX11;
|
|
|
|
break;
|
|
|
|
#if !PPSSPP_PLATFORM(UWP)
|
2015-10-10 14:41:19 +00:00
|
|
|
case GPUBackend::OPENGL:
|
2016-04-10 08:21:48 +00:00
|
|
|
coreParam.gpuCore = GPUCORE_GLES;
|
2015-10-10 14:41:19 +00:00
|
|
|
break;
|
|
|
|
case GPUBackend::DIRECT3D9:
|
2016-04-10 08:21:48 +00:00
|
|
|
coreParam.gpuCore = GPUCORE_DIRECTX9;
|
2015-10-10 14:41:19 +00:00
|
|
|
break;
|
|
|
|
case GPUBackend::VULKAN:
|
2016-04-10 08:21:48 +00:00
|
|
|
coreParam.gpuCore = GPUCORE_VULKAN;
|
2015-10-10 14:41:19 +00:00
|
|
|
break;
|
2017-02-24 19:50:27 +00:00
|
|
|
#endif
|
2014-08-17 19:29:36 +00:00
|
|
|
}
|
2016-02-13 20:22:06 +00:00
|
|
|
if (g_Config.bSoftwareRendering) {
|
2016-04-10 08:21:48 +00:00
|
|
|
coreParam.gpuCore = GPUCORE_SOFTWARE;
|
2016-02-13 20:22:06 +00:00
|
|
|
}
|
2016-01-03 19:05:36 +00:00
|
|
|
// Preserve the existing graphics context.
|
|
|
|
coreParam.graphicsContext = PSP_CoreParameter().graphicsContext;
|
2017-01-30 13:33:38 +00:00
|
|
|
coreParam.thin3d = screenManager()->getDrawContext();
|
2012-11-01 15:19:01 +00:00
|
|
|
coreParam.enableSound = g_Config.bEnableSound;
|
2014-01-19 22:17:34 +00:00
|
|
|
coreParam.fileToStart = filename;
|
2012-11-01 15:19:01 +00:00
|
|
|
coreParam.mountIso = "";
|
2014-04-19 19:52:43 +00:00
|
|
|
coreParam.mountRoot = "";
|
2012-11-01 15:19:01 +00:00
|
|
|
coreParam.startPaused = false;
|
|
|
|
coreParam.printfEmuLog = false;
|
|
|
|
coreParam.headLess = false;
|
2013-09-10 22:19:34 +00:00
|
|
|
|
2014-02-10 11:38:23 +00:00
|
|
|
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
|
|
|
|
|
2013-09-10 22:19:34 +00:00
|
|
|
if (g_Config.iInternalResolution == 0) {
|
2015-07-16 14:29:55 +00:00
|
|
|
coreParam.renderWidth = pixel_xres;
|
|
|
|
coreParam.renderHeight = pixel_yres;
|
2013-09-10 22:19:34 +00:00
|
|
|
} else {
|
|
|
|
if (g_Config.iInternalResolution < 0)
|
|
|
|
g_Config.iInternalResolution = 1;
|
|
|
|
coreParam.renderWidth = 480 * g_Config.iInternalResolution;
|
|
|
|
coreParam.renderHeight = 272 * g_Config.iInternalResolution;
|
|
|
|
}
|
2017-03-06 12:50:22 +00:00
|
|
|
coreParam.pixelWidth = pixel_xres;
|
|
|
|
coreParam.pixelHeight = pixel_yres;
|
2013-09-10 22:19:34 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
std::string error_string;
|
2014-01-19 22:17:34 +00:00
|
|
|
if (!PSP_InitStart(coreParam, &error_string)) {
|
2014-05-16 05:17:19 +00:00
|
|
|
bootPending_ = false;
|
2012-11-01 15:19:01 +00:00
|
|
|
invalid_ = true;
|
|
|
|
errorMessage_ = error_string;
|
|
|
|
ERROR_LOG(BOOT, "%s", errorMessage_.c_str());
|
2013-12-04 16:41:59 +00:00
|
|
|
System_SendMessage("event", "failstartgame");
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2017-03-14 09:36:51 +00:00
|
|
|
|
|
|
|
if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) {
|
|
|
|
I18NCategory *gr = GetI18NCategory("Graphics");
|
|
|
|
host->NotifyUserMessage(gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 15.0f);
|
|
|
|
}
|
2017-03-21 07:23:31 +00:00
|
|
|
|
|
|
|
if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.bBlockTransferGPU == false) {
|
|
|
|
I18NCategory *gr = GetI18NCategory("Graphics");
|
|
|
|
host->NotifyUserMessage(gr->T("BlockTransferRequired", "Warning: This game requires Simulate Block Transfer Mode to be set to On."), 15.0f);
|
|
|
|
}
|
2014-01-19 22:17:34 +00:00
|
|
|
}
|
2013-05-16 15:18:29 +00:00
|
|
|
|
2014-01-19 22:17:34 +00:00
|
|
|
void EmuScreen::bootComplete() {
|
2014-06-22 07:38:46 +00:00
|
|
|
UpdateUIState(UISTATE_INGAME);
|
2013-03-29 18:52:32 +00:00
|
|
|
host->BootDone();
|
2013-03-29 19:51:14 +00:00
|
|
|
host->UpdateDisassembly();
|
|
|
|
|
2016-02-14 21:07:10 +00:00
|
|
|
g_gameInfoCache->FlushBGs();
|
2013-04-13 19:24:07 +00:00
|
|
|
|
2014-01-19 22:17:34 +00:00
|
|
|
NOTICE_LOG(BOOT, "Loading %s...", PSP_CoreParameter().fileToStart.c_str());
|
2013-10-30 17:51:25 +00:00
|
|
|
autoLoad();
|
|
|
|
|
2016-08-28 04:20:03 +00:00
|
|
|
I18NCategory *sc = GetI18NCategory("Screen");
|
2013-06-10 22:51:10 +00:00
|
|
|
|
2014-02-08 19:11:50 +00:00
|
|
|
#ifndef MOBILE_DEVICE
|
2013-06-10 22:51:10 +00:00
|
|
|
if (g_Config.bFirstRun) {
|
2015-07-01 22:50:07 +00:00
|
|
|
osm.Show(sc->T("PressESC", "Press ESC to open the pause menu"), 3.0f);
|
2013-06-10 22:51:10 +00:00
|
|
|
}
|
|
|
|
#endif
|
2013-07-06 18:44:34 +00:00
|
|
|
memset(virtKeys, 0, sizeof(virtKeys));
|
2013-09-17 08:27:42 +00:00
|
|
|
|
2017-02-24 19:50:27 +00:00
|
|
|
#if !PPSSPP_PLATFORM(UWP)
|
2016-01-06 06:37:28 +00:00
|
|
|
if (GetGPUBackend() == GPUBackend::OPENGL) {
|
2014-08-17 19:29:36 +00:00
|
|
|
const char *renderer = (const char*)glGetString(GL_RENDERER);
|
|
|
|
if (strstr(renderer, "Chainfire3D") != 0) {
|
2015-07-01 22:50:07 +00:00
|
|
|
osm.Show(sc->T("Chainfire3DWarning", "WARNING: Chainfire3D detected, may cause problems"), 10.0f, 0xFF30a0FF, -1, true);
|
2014-08-17 19:29:36 +00:00
|
|
|
} else if (strstr(renderer, "GLTools") != 0) {
|
2015-07-01 22:50:07 +00:00
|
|
|
osm.Show(sc->T("GLToolsWarning", "WARNING: GLTools detected, may cause problems"), 10.0f, 0xFF30a0FF, -1, true);
|
2014-08-17 19:29:36 +00:00
|
|
|
}
|
2015-10-11 09:46:24 +00:00
|
|
|
|
|
|
|
if (g_Config.bGfxDebugOutput) {
|
|
|
|
osm.Show("WARNING: GfxDebugOutput is enabled via ppsspp.ini. Things may be slow.", 10.0f, 0xFF30a0FF, -1, true);
|
|
|
|
}
|
2013-09-17 08:27:42 +00:00
|
|
|
}
|
2017-02-24 19:50:27 +00:00
|
|
|
#endif
|
2013-10-30 17:16:27 +00:00
|
|
|
|
2016-07-25 00:04:06 +00:00
|
|
|
if (Core_GetPowerSaving()) {
|
|
|
|
I18NCategory *sy = GetI18NCategory("System");
|
2016-10-12 09:13:16 +00:00
|
|
|
#ifdef __ANDROID__
|
2016-10-11 00:32:25 +00:00
|
|
|
osm.Show(sy->T("WARNING: Android battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
|
|
|
|
#else
|
2016-07-25 00:04:06 +00:00
|
|
|
osm.Show(sy->T("WARNING: Battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
|
2016-10-11 00:32:25 +00:00
|
|
|
#endif
|
2016-07-25 00:04:06 +00:00
|
|
|
}
|
|
|
|
|
2013-12-04 16:41:59 +00:00
|
|
|
System_SendMessage("event", "startgame");
|
2016-08-17 04:24:01 +00:00
|
|
|
|
|
|
|
saveStateSlot_ = SaveState::GetCurrentSlot();
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 20:21:27 +00:00
|
|
|
EmuScreen::~EmuScreen() {
|
2012-11-01 15:19:01 +00:00
|
|
|
if (!invalid_) {
|
|
|
|
// If we were invalid, it would already be shutdown.
|
|
|
|
PSP_Shutdown();
|
|
|
|
}
|
2016-09-02 00:09:56 +00:00
|
|
|
#ifndef MOBILE_DEVICE
|
2016-08-27 18:38:05 +00:00
|
|
|
if (g_Config.bDumpFrames && startDumping)
|
|
|
|
{
|
|
|
|
avi.Stop();
|
2016-09-02 01:59:12 +00:00
|
|
|
osm.Show("AVI Dump stopped.", 3.0f);
|
2016-08-27 18:38:05 +00:00
|
|
|
startDumping = false;
|
|
|
|
}
|
2016-09-02 00:09:56 +00:00
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) {
|
2013-07-17 05:33:26 +00:00
|
|
|
// TODO: improve the way with which we got commands from PauseMenu.
|
2013-10-25 11:19:08 +00:00
|
|
|
// DR_CANCEL/DR_BACK means clicked on "continue", DR_OK means clicked on "back to menu",
|
2013-07-17 05:33:26 +00:00
|
|
|
// DR_YES means a message sent to PauseMenu by NativeMessageReceived.
|
2014-01-25 08:40:14 +00:00
|
|
|
if (result == DR_OK || quit_) {
|
2013-08-18 18:14:33 +00:00
|
|
|
screenManager()->switchScreen(new MainScreen());
|
2013-12-04 16:41:59 +00:00
|
|
|
System_SendMessage("event", "exitgame");
|
2014-01-25 08:40:14 +00:00
|
|
|
quit_ = false;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2013-07-20 10:06:06 +00:00
|
|
|
RecreateViews();
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2016-05-28 04:25:05 +00:00
|
|
|
static void AfterSaveStateAction(bool success, const std::string &message, void *) {
|
|
|
|
if (!message.empty()) {
|
|
|
|
osm.Show(message, 2.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AfterStateBoot(bool success, const std::string &message, void *ignored) {
|
|
|
|
AfterSaveStateAction(success, message, ignored);
|
2014-06-14 23:13:35 +00:00
|
|
|
Core_EnableStepping(false);
|
|
|
|
host->UpdateDisassembly();
|
|
|
|
}
|
|
|
|
|
2013-03-29 20:21:27 +00:00
|
|
|
void EmuScreen::sendMessage(const char *message, const char *value) {
|
2013-03-29 17:50:08 +00:00
|
|
|
// External commands, like from the Windows UI.
|
|
|
|
if (!strcmp(message, "pause")) {
|
2015-05-21 08:49:47 +00:00
|
|
|
releaseButtons();
|
2013-08-18 18:22:30 +00:00
|
|
|
screenManager()->push(new GamePauseScreen(gamePath_));
|
2015-05-21 08:49:47 +00:00
|
|
|
} else if (!strcmp(message, "lost_focus")) {
|
|
|
|
releaseButtons();
|
2013-03-29 17:50:08 +00:00
|
|
|
} else if (!strcmp(message, "stop")) {
|
2013-10-12 08:40:33 +00:00
|
|
|
// We will push MainScreen in update().
|
|
|
|
PSP_Shutdown();
|
2014-05-16 05:17:19 +00:00
|
|
|
bootPending_ = false;
|
2014-05-11 17:57:33 +00:00
|
|
|
invalid_ = true;
|
2014-07-06 21:02:45 +00:00
|
|
|
host->UpdateDisassembly();
|
2013-03-29 19:51:14 +00:00
|
|
|
} else if (!strcmp(message, "reset")) {
|
|
|
|
PSP_Shutdown();
|
2014-05-16 05:17:19 +00:00
|
|
|
bootPending_ = true;
|
2014-05-11 17:57:33 +00:00
|
|
|
invalid_ = true;
|
2014-07-06 21:02:45 +00:00
|
|
|
host->UpdateDisassembly();
|
|
|
|
|
2013-03-29 19:51:14 +00:00
|
|
|
std::string resetError;
|
2014-05-05 02:56:33 +00:00
|
|
|
if (!PSP_InitStart(PSP_CoreParameter(), &resetError)) {
|
2013-03-29 20:21:27 +00:00
|
|
|
ELOG("Error resetting: %s", resetError.c_str());
|
2013-08-18 18:14:33 +00:00
|
|
|
screenManager()->switchScreen(new MainScreen());
|
2013-12-04 16:41:59 +00:00
|
|
|
System_SendMessage("event", "failstartgame");
|
2013-03-29 19:51:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-11-20 06:44:12 +00:00
|
|
|
} else if (!strcmp(message, "boot")) {
|
2014-06-14 23:13:35 +00:00
|
|
|
const char *ext = strrchr(value, '.');
|
2015-03-01 00:05:13 +00:00
|
|
|
if (ext != nullptr && !strcmp(ext, ".ppst")) {
|
2016-05-28 04:25:05 +00:00
|
|
|
SaveState::Load(value, &AfterStateBoot);
|
2014-06-14 23:13:35 +00:00
|
|
|
} else {
|
|
|
|
PSP_Shutdown();
|
|
|
|
bootPending_ = true;
|
|
|
|
bootGame(value);
|
|
|
|
}
|
2013-11-20 06:44:12 +00:00
|
|
|
} else if (!strcmp(message, "control mapping")) {
|
2013-09-15 16:35:58 +00:00
|
|
|
UpdateUIState(UISTATE_MENU);
|
2015-05-21 08:49:47 +00:00
|
|
|
releaseButtons();
|
2013-09-07 15:29:44 +00:00
|
|
|
screenManager()->push(new ControlMappingScreen());
|
2015-12-21 05:32:05 +00:00
|
|
|
} else if (!strcmp(message, "display layout editor")) {
|
|
|
|
UpdateUIState(UISTATE_MENU);
|
|
|
|
releaseButtons();
|
|
|
|
screenManager()->push(new DisplayLayoutScreen());
|
2013-11-20 06:44:12 +00:00
|
|
|
} else if (!strcmp(message, "settings")) {
|
2013-09-15 16:35:58 +00:00
|
|
|
UpdateUIState(UISTATE_MENU);
|
2015-05-21 08:49:47 +00:00
|
|
|
releaseButtons();
|
2013-09-07 15:29:44 +00:00
|
|
|
screenManager()->push(new GameSettingsScreen(gamePath_));
|
2013-11-20 06:44:12 +00:00
|
|
|
} else if (!strcmp(message, "gpu dump next frame")) {
|
2015-05-21 08:49:47 +00:00
|
|
|
if (gpu)
|
|
|
|
gpu->DumpNextFrame();
|
2013-11-20 06:44:12 +00:00
|
|
|
} else if (!strcmp(message, "clear jit")) {
|
2014-12-12 22:48:48 +00:00
|
|
|
currentMIPS->ClearJitCache();
|
2014-05-28 06:02:28 +00:00
|
|
|
if (PSP_IsInited()) {
|
2016-05-07 23:43:27 +00:00
|
|
|
currentMIPS->UpdateCore((CPUCore)g_Config.iCpuCore);
|
2014-05-28 06:02:28 +00:00
|
|
|
}
|
2014-06-29 22:06:47 +00:00
|
|
|
} else if (!strcmp(message, "window minimized")) {
|
|
|
|
if (!strcmp(value, "true")) {
|
|
|
|
gstate_c.skipDrawReason |= SKIPDRAW_WINDOW_MINIMIZED;
|
|
|
|
} else {
|
|
|
|
gstate_c.skipDrawReason &= ~SKIPDRAW_WINDOW_MINIMIZED;
|
|
|
|
}
|
2016-10-25 10:35:52 +00:00
|
|
|
} else if (!strcmp(message, "chat screen")) {
|
|
|
|
releaseButtons();
|
2016-12-05 03:21:44 +00:00
|
|
|
#if defined(USING_WIN_UI)
|
|
|
|
//temporary workaround for hotkey its freeze the ui when open chat screen using hotkey and native keyboard is enable
|
|
|
|
if (g_Config.bBypassOSKWithKeyboard) {
|
|
|
|
osm.Show("Disable windows native keyboard options to use ctrl + c hotkey", 2.0f);
|
|
|
|
} else {
|
|
|
|
chatButtons->SetVisibility(UI::V_GONE);
|
|
|
|
screenManager()->push(new ChatMenu());
|
|
|
|
}
|
|
|
|
#else
|
2016-12-05 03:04:31 +00:00
|
|
|
chatButtons->SetVisibility(UI::V_GONE);
|
2016-10-31 14:22:57 +00:00
|
|
|
screenManager()->push(new ChatMenu());
|
2016-12-05 03:21:44 +00:00
|
|
|
#endif
|
2013-11-02 20:33:27 +00:00
|
|
|
}
|
2013-03-29 17:50:08 +00:00
|
|
|
}
|
|
|
|
|
2013-10-28 11:19:36 +00:00
|
|
|
//tiltInputCurve implements a smooth deadzone as described here:
|
2013-10-27 17:58:47 +00:00
|
|
|
//http://www.gamasutra.com/blogs/JoshSutphin/20130416/190541/Doing_Thumbstick_Dead_Zones_Right.php
|
2013-10-28 11:19:36 +00:00
|
|
|
inline float tiltInputCurve(float x) {
|
2013-10-28 11:15:27 +00:00
|
|
|
const float deadzone = g_Config.fDeadzoneRadius;
|
2013-03-10 12:21:36 +00:00
|
|
|
const float factor = 1.0f / (1.0f - deadzone);
|
2013-10-28 11:15:27 +00:00
|
|
|
|
2013-03-10 12:21:36 +00:00
|
|
|
if (x > deadzone) {
|
|
|
|
return (x - deadzone) * (x - deadzone) * factor;
|
2013-10-28 11:15:27 +00:00
|
|
|
} else if (x < -deadzone) {
|
2013-03-10 12:21:36 +00:00
|
|
|
return -(x + deadzone) * (x + deadzone) * factor;
|
|
|
|
} else {
|
|
|
|
return 0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline float clamp1(float x) {
|
|
|
|
if (x > 1.0f) return 1.0f;
|
|
|
|
if (x < -1.0f) return -1.0f;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2014-06-15 11:04:59 +00:00
|
|
|
bool EmuScreen::touch(const TouchInput &touch) {
|
2015-03-01 06:20:14 +00:00
|
|
|
Core_NotifyActivity();
|
|
|
|
|
2014-06-15 11:04:59 +00:00
|
|
|
if (root_) {
|
2013-07-27 15:25:22 +00:00
|
|
|
root_->Touch(touch);
|
2014-06-15 11:04:59 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2013-07-06 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
2013-07-07 08:42:39 +00:00
|
|
|
void EmuScreen::onVKeyDown(int virtualKeyCode) {
|
2016-08-28 04:20:03 +00:00
|
|
|
I18NCategory *sc = GetI18NCategory("Screen");
|
2013-07-07 12:08:08 +00:00
|
|
|
|
2013-07-07 08:42:39 +00:00
|
|
|
switch (virtualKeyCode) {
|
2013-07-20 12:05:07 +00:00
|
|
|
case VIRTKEY_UNTHROTTLE:
|
|
|
|
PSP_CoreParameter().unthrottle = true;
|
|
|
|
break;
|
|
|
|
|
2013-07-07 12:08:08 +00:00
|
|
|
case VIRTKEY_SPEED_TOGGLE:
|
|
|
|
if (PSP_CoreParameter().fpsLimit == 0) {
|
|
|
|
PSP_CoreParameter().fpsLimit = 1;
|
2015-07-01 22:50:07 +00:00
|
|
|
osm.Show(sc->T("fixed", "Speed: alternate"), 1.0);
|
2013-07-07 12:08:08 +00:00
|
|
|
}
|
|
|
|
else if (PSP_CoreParameter().fpsLimit == 1) {
|
|
|
|
PSP_CoreParameter().fpsLimit = 0;
|
2015-07-01 22:50:07 +00:00
|
|
|
osm.Show(sc->T("standard", "Speed: standard"), 1.0);
|
2013-07-07 12:08:08 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-07-08 15:46:20 +00:00
|
|
|
|
2013-07-07 12:08:08 +00:00
|
|
|
case VIRTKEY_PAUSE:
|
2013-10-22 14:18:43 +00:00
|
|
|
pauseTrigger_ = true;
|
2013-07-07 12:08:08 +00:00
|
|
|
break;
|
2013-07-07 23:25:15 +00:00
|
|
|
|
2016-08-28 04:20:03 +00:00
|
|
|
case VIRTKEY_FRAME_ADVANCE:
|
|
|
|
// If game is running, pause emulation immediately. Otherwise, advance a single frame.
|
|
|
|
if (Core_IsStepping())
|
|
|
|
{
|
|
|
|
frameStep_ = true;
|
|
|
|
Core_EnableStepping(false);
|
|
|
|
}
|
|
|
|
else if (!frameStep_)
|
|
|
|
{
|
|
|
|
Core_EnableStepping(true);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-11-07 12:40:53 +00:00
|
|
|
case VIRTKEY_AXIS_SWAP:
|
|
|
|
KeyMap::SwapAxis();
|
|
|
|
break;
|
|
|
|
|
2015-07-05 23:09:29 +00:00
|
|
|
case VIRTKEY_DEVMENU:
|
2017-04-18 03:33:22 +00:00
|
|
|
{
|
|
|
|
UI::EventParams e{};
|
|
|
|
OnDevMenu.Trigger(e);
|
2015-07-05 23:09:29 +00:00
|
|
|
break;
|
2017-04-18 03:33:22 +00:00
|
|
|
}
|
2015-07-05 23:09:29 +00:00
|
|
|
|
2013-07-07 23:25:15 +00:00
|
|
|
case VIRTKEY_AXIS_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_X_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogX(CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_Y_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogY(CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogX(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogY(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
2013-12-05 15:15:33 +00:00
|
|
|
|
2014-05-28 03:34:25 +00:00
|
|
|
case VIRTKEY_ANALOG_LIGHTLY:
|
|
|
|
setVKeyAnalogX(CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
|
|
|
|
setVKeyAnalogY(CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
|
|
|
|
setVKeyAnalogX(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
|
|
|
|
setVKeyAnalogY(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
|
|
|
|
break;
|
|
|
|
|
2013-12-05 15:15:33 +00:00
|
|
|
case VIRTKEY_REWIND:
|
|
|
|
if (SaveState::CanRewind()) {
|
2016-05-28 04:25:05 +00:00
|
|
|
SaveState::Rewind(&AfterSaveStateAction);
|
2013-12-05 15:15:33 +00:00
|
|
|
} else {
|
2015-07-01 22:50:07 +00:00
|
|
|
osm.Show(sc->T("norewind", "No rewind save states available"), 2.0);
|
2013-12-05 15:15:33 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-12-06 14:46:56 +00:00
|
|
|
case VIRTKEY_SAVE_STATE:
|
2016-05-28 04:25:05 +00:00
|
|
|
SaveState::SaveSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction);
|
2013-12-06 14:46:56 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_LOAD_STATE:
|
2016-05-28 04:25:05 +00:00
|
|
|
SaveState::LoadSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction);
|
2013-12-06 14:46:56 +00:00
|
|
|
break;
|
2014-01-07 14:56:04 +00:00
|
|
|
case VIRTKEY_NEXT_SLOT:
|
|
|
|
SaveState::NextSlot();
|
2016-05-28 03:53:20 +00:00
|
|
|
NativeMessageReceived("savestate_displayslot", "");
|
2014-01-07 14:56:04 +00:00
|
|
|
break;
|
2014-01-03 14:16:23 +00:00
|
|
|
case VIRTKEY_TOGGLE_FULLSCREEN:
|
|
|
|
System_SendMessage("toggle_fullscreen", "");
|
|
|
|
break;
|
2013-07-07 08:42:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmuScreen::onVKeyUp(int virtualKeyCode) {
|
|
|
|
switch (virtualKeyCode) {
|
2013-07-20 12:05:07 +00:00
|
|
|
case VIRTKEY_UNTHROTTLE:
|
|
|
|
PSP_CoreParameter().unthrottle = false;
|
|
|
|
break;
|
2013-07-20 19:11:35 +00:00
|
|
|
|
2013-07-07 23:25:15 +00:00
|
|
|
case VIRTKEY_AXIS_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_X_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogX(CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_Y_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogY(CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogX(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MAX:
|
2013-07-20 19:11:35 +00:00
|
|
|
setVKeyAnalogY(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
|
2013-07-07 23:25:15 +00:00
|
|
|
break;
|
2013-07-20 19:11:35 +00:00
|
|
|
|
2014-05-28 03:34:25 +00:00
|
|
|
case VIRTKEY_ANALOG_LIGHTLY:
|
|
|
|
setVKeyAnalogX(CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
|
|
|
|
setVKeyAnalogY(CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
|
|
|
|
setVKeyAnalogX(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
|
|
|
|
setVKeyAnalogY(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
|
|
|
|
break;
|
|
|
|
|
2013-07-07 22:07:45 +00:00
|
|
|
default:
|
2013-07-07 08:42:39 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-15 16:49:54 +00:00
|
|
|
// Handles control rotation due to internal screen rotation.
|
|
|
|
static void SetPSPAxis(char axis, float value, int stick) {
|
|
|
|
switch (g_Config.iInternalScreenRotation) {
|
|
|
|
case ROTATION_LOCKED_HORIZONTAL:
|
|
|
|
// Standard rotation.
|
|
|
|
break;
|
|
|
|
case ROTATION_LOCKED_HORIZONTAL180:
|
|
|
|
value = -value;
|
|
|
|
break;
|
|
|
|
case ROTATION_LOCKED_VERTICAL:
|
|
|
|
value = axis == 'Y' ? value : -value;
|
|
|
|
axis = (axis == 'X') ? 'Y' : 'X';
|
|
|
|
break;
|
|
|
|
case ROTATION_LOCKED_VERTICAL180:
|
|
|
|
value = axis == 'Y' ? -value : value;
|
|
|
|
axis = (axis == 'X') ? 'Y' : 'X';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (axis == 'X')
|
|
|
|
__CtrlSetAnalogX(value, stick);
|
|
|
|
else if (axis == 'Y')
|
|
|
|
__CtrlSetAnalogY(value, stick);
|
|
|
|
}
|
|
|
|
|
2013-07-20 19:11:35 +00:00
|
|
|
inline void EmuScreen::setVKeyAnalogX(int stick, int virtualKeyMin, int virtualKeyMax) {
|
2014-08-16 19:05:37 +00:00
|
|
|
const float value = virtKeys[VIRTKEY_ANALOG_LIGHTLY - VIRTKEY_FIRST] ? g_Config.fAnalogLimiterDeadzone : 1.0f;
|
2013-07-20 19:11:35 +00:00
|
|
|
float axis = 0.0f;
|
|
|
|
// The down events can repeat, so just trust the virtKeys array.
|
|
|
|
if (virtKeys[virtualKeyMin - VIRTKEY_FIRST])
|
2014-05-28 03:34:25 +00:00
|
|
|
axis -= value;
|
2013-07-20 19:11:35 +00:00
|
|
|
if (virtKeys[virtualKeyMax - VIRTKEY_FIRST])
|
2014-05-28 03:34:25 +00:00
|
|
|
axis += value;
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('X', axis, stick);
|
2013-07-20 19:11:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void EmuScreen::setVKeyAnalogY(int stick, int virtualKeyMin, int virtualKeyMax) {
|
2014-08-16 19:05:37 +00:00
|
|
|
const float value = virtKeys[VIRTKEY_ANALOG_LIGHTLY - VIRTKEY_FIRST] ? g_Config.fAnalogLimiterDeadzone : 1.0f;
|
2013-07-20 19:11:35 +00:00
|
|
|
float axis = 0.0f;
|
|
|
|
if (virtKeys[virtualKeyMin - VIRTKEY_FIRST])
|
2014-05-28 03:34:25 +00:00
|
|
|
axis -= value;
|
2013-07-20 19:11:35 +00:00
|
|
|
if (virtKeys[virtualKeyMax - VIRTKEY_FIRST])
|
2014-05-28 03:34:25 +00:00
|
|
|
axis += value;
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('Y', axis, stick);
|
2013-07-20 19:11:35 +00:00
|
|
|
}
|
|
|
|
|
2014-06-15 11:04:59 +00:00
|
|
|
bool EmuScreen::key(const KeyInput &key) {
|
2015-03-01 06:20:14 +00:00
|
|
|
Core_NotifyActivity();
|
|
|
|
|
2013-10-31 15:50:27 +00:00
|
|
|
std::vector<int> pspKeys;
|
|
|
|
KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &pspKeys);
|
2014-06-15 11:04:59 +00:00
|
|
|
|
|
|
|
if (pspKeys.size() && (key.flags & KEY_IS_REPEAT)) {
|
|
|
|
// Claim that we handled this. Prevents volume key repeats from popping up the volume control on Android.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-31 15:50:27 +00:00
|
|
|
for (size_t i = 0; i < pspKeys.size(); i++) {
|
|
|
|
pspKey(pspKeys[i], key.flags);
|
|
|
|
}
|
2015-01-02 15:43:08 +00:00
|
|
|
|
|
|
|
if (!pspKeys.size() || key.deviceId == DEVICE_ID_DEFAULT) {
|
|
|
|
if ((key.flags & KEY_DOWN) && key.keyCode == NKCODE_BACK) {
|
|
|
|
pauseTrigger_ = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-15 11:04:59 +00:00
|
|
|
return pspKeys.size() > 0;
|
2013-07-07 22:21:40 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 16:49:54 +00:00
|
|
|
static int RotatePSPKeyCode(int x) {
|
|
|
|
switch (x) {
|
|
|
|
case CTRL_UP: return CTRL_RIGHT;
|
|
|
|
case CTRL_RIGHT: return CTRL_DOWN;
|
|
|
|
case CTRL_DOWN: return CTRL_LEFT;
|
|
|
|
case CTRL_LEFT: return CTRL_UP;
|
|
|
|
default:
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-07 22:21:40 +00:00
|
|
|
void EmuScreen::pspKey(int pspKeyCode, int flags) {
|
2015-05-15 16:49:54 +00:00
|
|
|
int rotations = 0;
|
|
|
|
switch (g_Config.iInternalScreenRotation) {
|
|
|
|
case ROTATION_LOCKED_HORIZONTAL180:
|
|
|
|
rotations = 2;
|
|
|
|
break;
|
|
|
|
case ROTATION_LOCKED_VERTICAL:
|
|
|
|
rotations = 1;
|
|
|
|
break;
|
|
|
|
case ROTATION_LOCKED_VERTICAL180:
|
|
|
|
rotations = 3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < rotations; i++) {
|
|
|
|
pspKeyCode = RotatePSPKeyCode(pspKeyCode);
|
|
|
|
}
|
|
|
|
|
2013-07-07 22:21:40 +00:00
|
|
|
if (pspKeyCode >= VIRTKEY_FIRST) {
|
|
|
|
int vk = pspKeyCode - VIRTKEY_FIRST;
|
|
|
|
if (flags & KEY_DOWN) {
|
2013-07-07 08:42:39 +00:00
|
|
|
virtKeys[vk] = true;
|
2013-07-07 22:21:40 +00:00
|
|
|
onVKeyDown(pspKeyCode);
|
2013-07-07 08:42:39 +00:00
|
|
|
}
|
2013-07-07 22:21:40 +00:00
|
|
|
if (flags & KEY_UP) {
|
2013-07-07 08:42:39 +00:00
|
|
|
virtKeys[vk] = false;
|
2013-07-07 22:21:40 +00:00
|
|
|
onVKeyUp(pspKeyCode);
|
2013-07-07 08:42:39 +00:00
|
|
|
}
|
2013-07-06 18:44:34 +00:00
|
|
|
} else {
|
2013-08-06 09:09:09 +00:00
|
|
|
// ILOG("pspKey %i %i", pspKeyCode, flags);
|
2013-07-07 22:21:40 +00:00
|
|
|
if (flags & KEY_DOWN)
|
|
|
|
__CtrlButtonDown(pspKeyCode);
|
|
|
|
if (flags & KEY_UP)
|
|
|
|
__CtrlButtonUp(pspKeyCode);
|
2013-07-06 18:44:34 +00:00
|
|
|
}
|
2013-07-06 17:08:59 +00:00
|
|
|
}
|
|
|
|
|
2014-06-15 11:04:59 +00:00
|
|
|
bool EmuScreen::axis(const AxisInput &axis) {
|
2015-03-01 06:20:14 +00:00
|
|
|
Core_NotifyActivity();
|
|
|
|
|
2013-07-31 16:07:45 +00:00
|
|
|
if (axis.value > 0) {
|
|
|
|
processAxis(axis, 1);
|
2014-06-15 11:04:59 +00:00
|
|
|
return true;
|
2013-07-31 16:07:45 +00:00
|
|
|
} else if (axis.value < 0) {
|
|
|
|
processAxis(axis, -1);
|
2014-06-15 11:04:59 +00:00
|
|
|
return true;
|
2013-07-31 16:07:45 +00:00
|
|
|
} else if (axis.value == 0) {
|
|
|
|
// Both directions! Prevents sticking for digital input devices that are axises (like HAT)
|
|
|
|
processAxis(axis, 1);
|
|
|
|
processAxis(axis, -1);
|
2014-06-15 11:04:59 +00:00
|
|
|
return true;
|
2013-07-31 16:07:45 +00:00
|
|
|
}
|
2014-06-15 11:04:59 +00:00
|
|
|
return false;
|
2013-07-31 16:07:45 +00:00
|
|
|
}
|
|
|
|
|
2014-07-20 10:42:30 +00:00
|
|
|
inline bool IsAnalogStickKey(int key) {
|
|
|
|
switch (key) {
|
|
|
|
case VIRTKEY_AXIS_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_X_MAX:
|
|
|
|
case VIRTKEY_AXIS_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_Y_MAX:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MAX:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MIN:
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MAX:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-31 16:07:45 +00:00
|
|
|
void EmuScreen::processAxis(const AxisInput &axis, int direction) {
|
2014-07-20 10:52:11 +00:00
|
|
|
// Sanity check
|
|
|
|
if (axis.axisId < 0 || axis.axisId >= JOYSTICK_AXIS_MAX) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-31 15:50:27 +00:00
|
|
|
std::vector<int> results;
|
|
|
|
KeyMap::AxisToPspButton(axis.deviceId, axis.axisId, direction, &results);
|
2015-05-15 16:49:54 +00:00
|
|
|
|
2013-10-31 15:50:27 +00:00
|
|
|
for (size_t i = 0; i < results.size(); i++) {
|
|
|
|
int result = results[i];
|
|
|
|
switch (result) {
|
|
|
|
case VIRTKEY_AXIS_X_MIN:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('X', -fabs(axis.value), CTRL_STICK_LEFT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_X_MAX:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('X', fabs(axis.value), CTRL_STICK_LEFT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_Y_MIN:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('Y', -fabs(axis.value), CTRL_STICK_LEFT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_Y_MAX:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('Y', fabs(axis.value), CTRL_STICK_LEFT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MIN:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('X', -fabs(axis.value), CTRL_STICK_RIGHT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_X_MAX:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('X', fabs(axis.value), CTRL_STICK_RIGHT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MIN:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('Y', -fabs(axis.value), CTRL_STICK_RIGHT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
|
|
|
case VIRTKEY_AXIS_RIGHT_Y_MAX:
|
2015-05-15 16:49:54 +00:00
|
|
|
SetPSPAxis('Y', fabs(axis.value), CTRL_STICK_RIGHT);
|
2013-10-31 15:50:27 +00:00
|
|
|
break;
|
2014-07-20 10:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
2013-10-31 15:50:27 +00:00
|
|
|
|
2014-07-20 10:42:30 +00:00
|
|
|
std::vector<int> resultsOpposite;
|
|
|
|
KeyMap::AxisToPspButton(axis.deviceId, axis.axisId, -direction, &resultsOpposite);
|
|
|
|
|
2014-07-20 10:52:11 +00:00
|
|
|
int axisState = 0;
|
|
|
|
if ((direction == 1 && axis.value >= AXIS_BIND_THRESHOLD)) {
|
|
|
|
axisState = 1;
|
|
|
|
} else if (direction == -1 && axis.value <= -AXIS_BIND_THRESHOLD) {
|
|
|
|
axisState = -1;
|
2014-07-20 10:42:30 +00:00
|
|
|
} else {
|
2014-07-20 10:52:11 +00:00
|
|
|
axisState = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (axisState != axisState_[axis.axisId]) {
|
|
|
|
axisState_[axis.axisId] = axisState;
|
|
|
|
if (axisState != 0) {
|
|
|
|
for (size_t i = 0; i < results.size(); i++) {
|
|
|
|
if (!IsAnalogStickKey(results[i]))
|
|
|
|
pspKey(results[i], KEY_DOWN);
|
|
|
|
}
|
2014-12-22 02:50:07 +00:00
|
|
|
// Also unpress the other direction (unless both directions press the same key.)
|
2014-07-20 10:52:11 +00:00
|
|
|
for (size_t i = 0; i < resultsOpposite.size(); i++) {
|
2014-12-22 02:50:07 +00:00
|
|
|
if (!IsAnalogStickKey(resultsOpposite[i]) && std::find(results.begin(), results.end(), resultsOpposite[i]) == results.end())
|
2014-07-20 10:52:11 +00:00
|
|
|
pspKey(resultsOpposite[i], KEY_UP);
|
|
|
|
}
|
|
|
|
} else if (axisState == 0) {
|
|
|
|
// Release both directions, trying to deal with some erratic controllers that can cause it to stick.
|
|
|
|
for (size_t i = 0; i < results.size(); i++) {
|
|
|
|
if (!IsAnalogStickKey(results[i]))
|
|
|
|
pspKey(results[i], KEY_UP);
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < resultsOpposite.size(); i++) {
|
|
|
|
if (!IsAnalogStickKey(resultsOpposite[i]))
|
|
|
|
pspKey(resultsOpposite[i], KEY_UP);
|
|
|
|
}
|
2013-07-07 22:21:40 +00:00
|
|
|
}
|
2013-07-06 17:08:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-20 10:06:06 +00:00
|
|
|
void EmuScreen::CreateViews() {
|
2015-02-01 17:04:06 +00:00
|
|
|
using namespace UI;
|
2016-10-21 13:12:57 +00:00
|
|
|
I18NCategory *sc = GetI18NCategory("Screen");
|
2014-02-10 14:55:21 +00:00
|
|
|
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
|
|
|
|
InitPadLayout(bounds.w, bounds.h);
|
|
|
|
root_ = CreatePadLayout(bounds.w, bounds.h, &pauseTrigger_);
|
2013-09-07 18:54:11 +00:00
|
|
|
if (g_Config.bShowDeveloperMenu) {
|
2015-02-01 17:04:06 +00:00
|
|
|
root_->Add(new Button("DevMenu"))->OnClick.Handle(this, &EmuScreen::OnDevTools);
|
2013-09-07 18:54:11 +00:00
|
|
|
}
|
2016-10-22 16:06:07 +00:00
|
|
|
if (g_Config.bEnableNetworkChat) {
|
2016-12-05 03:04:31 +00:00
|
|
|
switch (g_Config.iChatButtonPosition) {
|
|
|
|
case 0:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, 80, NONE, NONE, 50, true));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, bounds.centerX(), NONE, NONE, 50, true));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, NONE, NONE, 80, 50, true));
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, 80, 50, NONE, NONE, true));
|
|
|
|
case 4:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, bounds.centerX(), 50, NONE, NONE, true));
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, NONE, 50, 80, NONE, true));
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, 80, bounds.centerY(), NONE, NONE, true));
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, NONE, bounds.centerY(), 80, NONE, true));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
chatButtons = new ChoiceWithValueDisplay(&newChat, sc->T("Chat"), new AnchorLayoutParams(130, WRAP_CONTENT, 80, NONE, NONE, 50, true));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
root_->Add(chatButtons)->OnClick.Handle(this, &EmuScreen::OnChat);
|
2016-10-22 16:06:07 +00:00
|
|
|
}
|
2015-02-01 17:04:06 +00:00
|
|
|
saveStatePreview_ = new AsyncImageFileView("", IS_FIXED, nullptr, new AnchorLayoutParams(bounds.centerX(), 100, NONE, NONE, true));
|
|
|
|
saveStatePreview_->SetFixedSize(160, 90);
|
|
|
|
saveStatePreview_->SetColor(0x90FFFFFF);
|
|
|
|
saveStatePreview_->SetVisibility(V_GONE);
|
2015-02-02 09:05:23 +00:00
|
|
|
saveStatePreview_->SetCanBeFocused(false);
|
2015-02-01 17:04:06 +00:00
|
|
|
root_->Add(saveStatePreview_);
|
|
|
|
root_->Add(new OnScreenMessagesView(new AnchorLayoutParams((Size)bounds.w, (Size)bounds.h)));
|
2013-09-07 18:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UI::EventReturn EmuScreen::OnDevTools(UI::EventParams ¶ms) {
|
2015-05-21 08:49:47 +00:00
|
|
|
releaseButtons();
|
2017-03-22 01:27:57 +00:00
|
|
|
DevMenu *devMenu = new DevMenu();
|
|
|
|
if (params.v)
|
|
|
|
devMenu->SetPopupOrigin(params.v);
|
|
|
|
screenManager()->push(devMenu);
|
2013-09-07 18:54:11 +00:00
|
|
|
return UI::EVENT_DONE;
|
2013-07-20 10:06:06 +00:00
|
|
|
}
|
|
|
|
|
2016-10-21 10:35:54 +00:00
|
|
|
UI::EventReturn EmuScreen::OnChat(UI::EventParams ¶ms) {
|
|
|
|
releaseButtons();
|
2016-12-05 03:04:31 +00:00
|
|
|
if(chatButtons->GetVisibility() == UI::V_VISIBLE) chatButtons->SetVisibility(UI::V_GONE);
|
2016-10-31 14:22:57 +00:00
|
|
|
screenManager()->push(new ChatMenu());
|
2016-10-21 10:35:54 +00:00
|
|
|
return UI::EVENT_DONE;
|
|
|
|
}
|
|
|
|
|
2017-03-15 05:01:18 +00:00
|
|
|
void EmuScreen::update() {
|
2016-10-21 10:35:54 +00:00
|
|
|
|
2014-05-16 05:17:19 +00:00
|
|
|
if (bootPending_)
|
2013-07-27 11:26:26 +00:00
|
|
|
bootGame(gamePath_);
|
|
|
|
|
2017-03-15 05:01:18 +00:00
|
|
|
UIScreen::update();
|
2013-07-20 10:06:06 +00:00
|
|
|
|
2016-03-20 08:52:13 +00:00
|
|
|
// Simply forcibly update to the current screen size every frame. Doesn't cost much.
|
2014-02-10 14:14:45 +00: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 12:50:22 +00:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
2014-02-10 14:14:45 +00:00
|
|
|
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
|
|
|
|
PSP_CoreParameter().pixelWidth = pixel_xres * bounds.w / dp_xres;
|
|
|
|
PSP_CoreParameter().pixelHeight = pixel_yres * bounds.h / dp_yres;
|
2017-03-06 12:50:22 +00:00
|
|
|
#endif
|
2013-07-16 20:50:53 +00:00
|
|
|
|
2014-05-21 08:13:40 +00:00
|
|
|
if (!invalid_) {
|
|
|
|
UpdateUIState(UISTATE_INGAME);
|
|
|
|
}
|
2013-11-15 12:11:44 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
if (errorMessage_.size()) {
|
2013-12-05 13:14:15 +00:00
|
|
|
// Special handling for ZIP files. It's not very robust to check an error message but meh,
|
|
|
|
// at least it's pre-translation.
|
|
|
|
if (errorMessage_.find("ZIP") != std::string::npos) {
|
|
|
|
screenManager()->push(new InstallZipScreen(gamePath_));
|
|
|
|
errorMessage_ = "";
|
2014-01-25 08:40:14 +00:00
|
|
|
quit_ = true;
|
2013-12-05 13:14:15 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-07-01 21:34:50 +00:00
|
|
|
I18NCategory *err = GetI18NCategory("Error");
|
|
|
|
std::string errLoadingFile = err->T("Error loading file", "Could not load game");
|
2013-12-05 13:14:15 +00:00
|
|
|
|
2013-08-22 19:37:49 +00:00
|
|
|
errLoadingFile.append(" ");
|
2015-07-01 21:34:50 +00:00
|
|
|
errLoadingFile.append(err->T(errorMessage_.c_str()));
|
2013-08-22 19:37:49 +00:00
|
|
|
|
2013-12-05 13:14:15 +00:00
|
|
|
screenManager()->push(new PromptScreen(errLoadingFile, "OK", ""));
|
2012-11-01 15:19:01 +00:00
|
|
|
errorMessage_ = "";
|
2014-01-25 08:40:14 +00:00
|
|
|
quit_ = true;
|
2012-11-01 15:19:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (invalid_)
|
|
|
|
return;
|
2012-12-26 07:51:03 +00:00
|
|
|
|
2013-07-06 18:44:34 +00:00
|
|
|
// Virtual keys.
|
2013-07-07 02:41:28 +00:00
|
|
|
__CtrlSetRapidFire(virtKeys[VIRTKEY_RAPID_FIRE - VIRTKEY_FIRST]);
|
2013-07-06 18:44:34 +00:00
|
|
|
|
2013-05-10 00:36:23 +00:00
|
|
|
// Make sure fpsLimit starts at 0
|
2013-07-11 19:55:33 +00:00
|
|
|
if (PSP_CoreParameter().fpsLimit != 0 && PSP_CoreParameter().fpsLimit != 1) {
|
2013-05-10 00:36:23 +00:00
|
|
|
PSP_CoreParameter().fpsLimit = 0;
|
|
|
|
}
|
2013-06-17 18:28:22 +00:00
|
|
|
|
2013-07-20 12:05:07 +00:00
|
|
|
// This is here to support the iOS on screen back button.
|
|
|
|
if (pauseTrigger_) {
|
|
|
|
pauseTrigger_ = false;
|
2015-05-21 08:49:47 +00:00
|
|
|
releaseButtons();
|
2013-08-18 18:14:33 +00:00
|
|
|
screenManager()->push(new GamePauseScreen(gamePath_));
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2015-02-01 17:04:06 +00:00
|
|
|
|
2016-08-17 04:24:01 +00:00
|
|
|
if (saveStatePreview_ && !bootPending_) {
|
2016-05-28 03:41:37 +00:00
|
|
|
int currentSlot = SaveState::GetCurrentSlot();
|
|
|
|
if (saveStateSlot_ != currentSlot) {
|
|
|
|
saveStateSlot_ = currentSlot;
|
|
|
|
|
|
|
|
std::string fn;
|
|
|
|
if (SaveState::HasSaveInSlot(gamePath_, currentSlot)) {
|
|
|
|
fn = SaveState::GenerateSaveSlotFilename(gamePath_, currentSlot, SaveState::SCREENSHOT_EXTENSION);
|
|
|
|
}
|
|
|
|
|
|
|
|
saveStatePreview_->SetFilename(fn);
|
|
|
|
if (!fn.empty()) {
|
|
|
|
saveStatePreview_->SetVisibility(UI::V_VISIBLE);
|
|
|
|
saveStatePreviewShownTime_ = time_now_d();
|
|
|
|
} else {
|
|
|
|
saveStatePreview_->SetVisibility(UI::V_GONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 03:53:58 +00:00
|
|
|
if (saveStatePreview_->GetVisibility() == UI::V_VISIBLE) {
|
|
|
|
double endTime = saveStatePreviewShownTime_ + 2.0;
|
|
|
|
float alpha = clamp_value((endTime - time_now_d()) * 4.0, 0.0, 1.0);
|
|
|
|
saveStatePreview_->SetColor(colorAlpha(0x00FFFFFF, alpha));
|
|
|
|
|
|
|
|
if (time_now_d() - saveStatePreviewShownTime_ > 2) {
|
|
|
|
saveStatePreview_->SetVisibility(UI::V_GONE);
|
|
|
|
}
|
2016-05-28 03:41:37 +00:00
|
|
|
}
|
2015-02-01 17:04:06 +00:00
|
|
|
}
|
2016-12-05 03:04:31 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2014-05-21 08:13:40 +00:00
|
|
|
void EmuScreen::checkPowerDown() {
|
|
|
|
if (coreState == CORE_POWERDOWN && !PSP_IsIniting()) {
|
|
|
|
if (PSP_IsInited()) {
|
|
|
|
PSP_Shutdown();
|
|
|
|
}
|
|
|
|
ILOG("SELF-POWERDOWN!");
|
|
|
|
screenManager()->switchScreen(new MainScreen());
|
|
|
|
bootPending_ = false;
|
|
|
|
invalid_ = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-29 11:55:49 +00:00
|
|
|
static void DrawDebugStats(DrawBuffer *draw2d) {
|
2016-03-31 08:17:02 +00:00
|
|
|
char statbuf[4096];
|
2015-01-29 11:55:49 +00:00
|
|
|
__DisplayGetDebugStats(statbuf, sizeof(statbuf));
|
|
|
|
draw2d->SetFontScale(.7f, .7f);
|
|
|
|
draw2d->DrawText(UBUNTU24, statbuf, 11, 31, 0xc0000000, FLAG_DYNAMIC_ASCII);
|
|
|
|
draw2d->DrawText(UBUNTU24, statbuf, 10, 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
2015-10-28 20:20:20 +00:00
|
|
|
|
|
|
|
__SasGetDebugStats(statbuf, sizeof(statbuf));
|
|
|
|
draw2d->DrawText(UBUNTU24, statbuf, PSP_CoreParameter().pixelWidth / 2 + 11, 31, 0xc0000000, FLAG_DYNAMIC_ASCII);
|
|
|
|
draw2d->DrawText(UBUNTU24, statbuf, PSP_CoreParameter().pixelWidth / 2 + 10, 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
2015-01-29 11:55:49 +00:00
|
|
|
draw2d->SetFontScale(1.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DrawAudioDebugStats(DrawBuffer *draw2d) {
|
|
|
|
char statbuf[1024] = { 0 };
|
|
|
|
const AudioDebugStats *stats = __AudioGetDebugStats();
|
|
|
|
snprintf(statbuf, sizeof(statbuf),
|
|
|
|
"Audio buffer: %d/%d (low watermark: %d)\n"
|
|
|
|
"Underruns: %d\n"
|
|
|
|
"Overruns: %d\n"
|
|
|
|
"Sample rate: %d\n"
|
|
|
|
"Push size: %d\n",
|
|
|
|
stats->buffered, stats->bufsize, stats->watermark,
|
|
|
|
stats->underrunCount,
|
|
|
|
stats->overrunCount,
|
|
|
|
stats->instantSampleRate,
|
|
|
|
stats->lastPushSize);
|
|
|
|
draw2d->SetFontScale(0.7f, 0.7f);
|
|
|
|
draw2d->DrawText(UBUNTU24, statbuf, 11, 31, 0xc0000000, FLAG_DYNAMIC_ASCII);
|
|
|
|
draw2d->DrawText(UBUNTU24, statbuf, 10, 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
|
|
|
draw2d->SetFontScale(1.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DrawFPS(DrawBuffer *draw2d, const Bounds &bounds) {
|
|
|
|
float vps, fps, actual_fps;
|
|
|
|
__DisplayGetFPS(&vps, &fps, &actual_fps);
|
|
|
|
char fpsbuf[256];
|
|
|
|
switch (g_Config.iShowFPSCounter) {
|
|
|
|
case 1:
|
|
|
|
snprintf(fpsbuf, sizeof(fpsbuf), "Speed: %0.1f%%", vps / (59.94f / 100.0f)); break;
|
|
|
|
case 2:
|
|
|
|
snprintf(fpsbuf, sizeof(fpsbuf), "FPS: %0.1f", actual_fps); break;
|
|
|
|
case 3:
|
|
|
|
snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / (59.94f / 100.0f)); break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
draw2d->SetFontScale(0.7f, 0.7f);
|
|
|
|
draw2d->DrawText(UBUNTU24, fpsbuf, bounds.x2() - 8, 12, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
|
|
|
draw2d->DrawText(UBUNTU24, fpsbuf, bounds.x2() - 10, 10, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
|
|
|
draw2d->SetFontScale(1.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
2017-05-16 12:24:40 +00:00
|
|
|
void EmuScreen::preRender() {
|
|
|
|
using namespace Draw;
|
|
|
|
DrawContext *draw = screenManager()->getDrawContext();
|
|
|
|
draw->BeginFrame();
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
2017-06-01 02:46:59 +00:00
|
|
|
if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) {
|
2017-05-16 12:24:40 +00:00
|
|
|
// We need to clear here already so that drawing during the frame is done on a clean slate.
|
|
|
|
DrawContext *draw = screenManager()->getDrawContext();
|
2017-05-16 14:00:34 +00:00
|
|
|
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 });
|
2017-05-16 12:24:40 +00:00
|
|
|
|
|
|
|
Viewport viewport;
|
|
|
|
viewport.TopLeftX = 0;
|
|
|
|
viewport.TopLeftY = 0;
|
|
|
|
viewport.Width = pixel_xres;
|
|
|
|
viewport.Height = pixel_yres;
|
|
|
|
viewport.MaxDepth = 1.0;
|
|
|
|
viewport.MinDepth = 0.0;
|
|
|
|
draw->SetViewports(1, &viewport);
|
|
|
|
draw->SetTargetSize(pixel_xres, pixel_yres);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmuScreen::postRender() {
|
|
|
|
Draw::DrawContext *draw = screenManager()->getDrawContext();
|
|
|
|
if (!draw)
|
|
|
|
return;
|
|
|
|
draw->EndFrame();
|
|
|
|
}
|
|
|
|
|
2013-03-29 20:21:27 +00:00
|
|
|
void EmuScreen::render() {
|
2016-12-25 17:18:19 +00:00
|
|
|
using namespace Draw;
|
|
|
|
|
2014-05-21 08:13:40 +00:00
|
|
|
if (invalid_) {
|
|
|
|
// It's possible this might be set outside PSP_RunLoopFor().
|
|
|
|
// In this case, we need to double check it here.
|
|
|
|
checkPowerDown();
|
2012-11-01 15:19:01 +00:00
|
|
|
return;
|
2014-05-21 08:13:40 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-11-15 12:11:44 +00:00
|
|
|
if (PSP_CoreParameter().freezeNext) {
|
|
|
|
PSP_CoreParameter().frozen = true;
|
|
|
|
PSP_CoreParameter().freezeNext = false;
|
|
|
|
SaveState::SaveToRam(freezeState_);
|
|
|
|
} else if (PSP_CoreParameter().frozen) {
|
|
|
|
if (CChunkFileReader::ERROR_NONE != SaveState::LoadFromRam(freezeState_)) {
|
2017-03-06 12:10:23 +00:00
|
|
|
ERROR_LOG(SAVESTATE, "Failed to load freeze state. Unfreezing.");
|
2013-11-15 12:11:44 +00:00
|
|
|
PSP_CoreParameter().frozen = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-06 22:49:02 +00:00
|
|
|
PSP_BeginHostFrame();
|
2012-11-25 16:21:23 +00:00
|
|
|
|
2012-12-01 22:20:08 +00:00
|
|
|
// We just run the CPU until we get to vblank. This will quickly sync up pretty nicely.
|
2012-11-20 10:35:48 +00:00
|
|
|
// The actual number of cycles doesn't matter so much here as we will break due to CORE_NEXTFRAME, most of the time hopefully...
|
2013-02-18 22:22:41 +00:00
|
|
|
int blockTicks = usToCycles(1000000 / 10);
|
2012-11-19 13:16:37 +00:00
|
|
|
|
2012-11-19 13:51:47 +00:00
|
|
|
// Run until CORE_NEXTFRAME
|
|
|
|
while (coreState == CORE_RUNNING) {
|
2013-08-04 22:22:30 +00:00
|
|
|
PSP_RunLoopFor(blockTicks);
|
2012-11-19 13:51:47 +00:00
|
|
|
}
|
2016-01-06 22:08:26 +00:00
|
|
|
|
2012-11-19 13:51:47 +00:00
|
|
|
// Hopefully coreState is now CORE_NEXTFRAME
|
|
|
|
if (coreState == CORE_NEXTFRAME) {
|
|
|
|
// set back to running for the next frame
|
|
|
|
coreState = CORE_RUNNING;
|
2012-11-19 13:16:37 +00:00
|
|
|
}
|
2014-05-21 08:13:40 +00:00
|
|
|
checkPowerDown();
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2016-01-06 22:49:02 +00:00
|
|
|
PSP_EndHostFrame();
|
|
|
|
|
2013-03-06 23:10:53 +00:00
|
|
|
if (invalid_)
|
|
|
|
return;
|
2017-05-16 12:24:40 +00:00
|
|
|
|
|
|
|
// Here the backbuffer will always be bound.
|
2013-03-06 23:10:53 +00:00
|
|
|
|
2015-05-13 20:28:02 +00:00
|
|
|
if (!osm.IsEmpty() || g_Config.bShowDebugStats || g_Config.iShowFPSCounter || g_Config.bShowTouchControls || g_Config.bShowDeveloperMenu || g_Config.bShowAudioDebug || saveStatePreview_->GetVisibility() != UI::V_GONE || g_Config.bShowFrameProfiler) {
|
2017-01-30 13:33:38 +00:00
|
|
|
DrawContext *thin3d = screenManager()->getDrawContext();
|
2015-01-04 17:00:59 +00:00
|
|
|
|
2015-02-03 20:59:36 +00:00
|
|
|
// This sets up some important states but not the viewport.
|
2015-01-04 17:00:59 +00:00
|
|
|
screenManager()->getUIContext()->Begin();
|
|
|
|
|
2016-12-25 17:52:05 +00:00
|
|
|
Viewport viewport;
|
2015-01-04 17:00:59 +00:00
|
|
|
viewport.TopLeftX = 0;
|
|
|
|
viewport.TopLeftY = 0;
|
|
|
|
viewport.Width = pixel_xres;
|
|
|
|
viewport.Height = pixel_yres;
|
|
|
|
viewport.MaxDepth = 1.0;
|
|
|
|
viewport.MinDepth = 0.0;
|
|
|
|
thin3d->SetViewports(1, &viewport);
|
|
|
|
|
|
|
|
DrawBuffer *draw2d = screenManager()->getUIContext()->Draw();
|
2012-11-20 10:35:48 +00:00
|
|
|
|
2014-12-31 15:50:23 +00:00
|
|
|
if (root_) {
|
|
|
|
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_);
|
|
|
|
root_->Draw(*screenManager()->getUIContext());
|
2013-06-19 05:08:29 +00:00
|
|
|
}
|
2014-02-10 11:38:23 +00:00
|
|
|
|
2014-12-31 15:50:23 +00:00
|
|
|
if (g_Config.bShowDebugStats) {
|
2015-01-29 11:55:49 +00:00
|
|
|
DrawDebugStats(draw2d);
|
2014-12-31 15:50:23 +00:00
|
|
|
}
|
2013-10-27 09:50:45 +00:00
|
|
|
|
2015-01-29 11:55:49 +00:00
|
|
|
if (g_Config.bShowAudioDebug) {
|
|
|
|
DrawAudioDebugStats(draw2d);
|
|
|
|
}
|
2014-12-31 15:50:23 +00:00
|
|
|
|
2015-01-29 11:55:49 +00:00
|
|
|
if (g_Config.iShowFPSCounter) {
|
|
|
|
DrawFPS(draw2d, screenManager()->getUIContext()->GetBounds());
|
2014-12-31 15:50:23 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2015-05-13 21:07:19 +00:00
|
|
|
#ifdef USE_PROFILER
|
2015-05-13 20:28:02 +00:00
|
|
|
if (g_Config.bShowFrameProfiler) {
|
2015-05-13 21:07:19 +00:00
|
|
|
DrawProfile(*screenManager()->getUIContext());
|
2015-05-13 20:28:02 +00:00
|
|
|
}
|
2015-05-13 21:07:19 +00:00
|
|
|
#endif
|
2015-05-13 20:28:02 +00:00
|
|
|
|
2015-01-04 17:00:59 +00:00
|
|
|
screenManager()->getUIContext()->End();
|
2014-12-31 15:50:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We have no use for backbuffer depth or stencil, so let tiled renderers discard them after tiling.
|
2015-10-10 14:41:19 +00:00
|
|
|
/*
|
2014-12-31 15:50:23 +00:00
|
|
|
if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) {
|
2015-03-14 23:01:43 +00:00
|
|
|
GLenum attachments[2] = { GL_DEPTH, GL_STENCIL };
|
|
|
|
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
|
2014-12-31 15:50:23 +00:00
|
|
|
} else if (!gl_extensions.GLES3) {
|
2015-09-05 21:09:06 +00:00
|
|
|
#ifdef USING_GLES2
|
2014-12-31 15:50:23 +00:00
|
|
|
// Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it?
|
|
|
|
bool hasDiscard = gl_extensions.EXT_discard_framebuffer; // TODO
|
|
|
|
if (hasDiscard) {
|
|
|
|
//const GLenum targets[3] = { GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT };
|
|
|
|
//glDiscardFramebufferEXT(GL_FRAMEBUFFER, 3, targets);
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
2015-09-05 21:09:06 +00:00
|
|
|
}
|
2015-10-10 14:41:19 +00:00
|
|
|
*/
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 20:21:27 +00:00
|
|
|
void EmuScreen::deviceLost() {
|
2013-03-06 23:10:53 +00:00
|
|
|
ILOG("EmuScreen::deviceLost()");
|
2013-07-27 08:05:00 +00:00
|
|
|
if (gpu)
|
|
|
|
gpu->DeviceLost();
|
2016-09-11 03:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmuScreen::deviceRestore() {
|
|
|
|
ILOG("EmuScreen::deviceRestore()");
|
|
|
|
if (gpu)
|
|
|
|
gpu->DeviceRestore();
|
2013-12-10 23:47:36 +00:00
|
|
|
|
|
|
|
RecreateViews();
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2013-10-30 17:16:27 +00:00
|
|
|
|
2013-10-30 17:54:41 +00:00
|
|
|
void EmuScreen::autoLoad() {
|
2013-10-30 17:16:27 +00:00
|
|
|
//check if save state has save, if so, load
|
2015-09-23 17:29:39 +00:00
|
|
|
int lastSlot = SaveState::GetNewestSlot(gamePath_);
|
2013-10-30 17:52:46 +00:00
|
|
|
if (g_Config.bEnableAutoLoad && lastSlot != -1) {
|
2016-05-28 04:25:05 +00:00
|
|
|
SaveState::LoadSlot(gamePath_, lastSlot, &AfterSaveStateAction);
|
2014-07-15 12:14:35 +00:00
|
|
|
g_Config.iCurrentStateSlot = lastSlot;
|
2013-10-30 17:16:27 +00:00
|
|
|
}
|
2013-12-15 11:49:13 +00:00
|
|
|
}
|
2015-05-21 08:49:47 +00:00
|
|
|
|
|
|
|
// TODO: Add generic loss-of-focus handling for Screens, use this.
|
|
|
|
void EmuScreen::releaseButtons() {
|
|
|
|
TouchInput input;
|
|
|
|
input.flags = TOUCH_RELEASE_ALL;
|
|
|
|
input.timestamp = time_now_d();
|
|
|
|
input.id = 0;
|
|
|
|
touch(input);
|
2015-05-13 21:07:19 +00:00
|
|
|
}
|
2017-02-23 08:25:33 +00:00
|
|
|
|
|
|
|
void EmuScreen::resized() {
|
|
|
|
RecreateViews();
|
2017-03-15 03:52:30 +00:00
|
|
|
}
|