ppsspp/UI/EmuScreen.cpp

310 lines
8.3 KiB
C++
Raw Normal View History

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
// 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/.
#include "base/logging.h"
2012-11-01 15:19:01 +00:00
#include "gfx_es2/glsl_program.h"
#include "gfx_es2/gl_state.h"
#include "gfx_es2/fbo.h"
2012-11-01 15:19:01 +00:00
#include "input/input_state.h"
#include "ui/ui.h"
#include "Core/Config.h"
#include "Core/CoreTiming.h"
#include "Core/CoreParameter.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "Core/System.h"
#include "Core/MIPS/MIPS.h"
#include "GPU/GPUState.h"
#include "GPU/GPUInterface.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/Debugger/SymbolMap.h"
2012-11-01 15:19:01 +00:00
#include "UI/ui_atlas.h"
#include "UI/GamepadEmu.h"
#include "UI/UIShader.h"
2012-11-01 15:19:01 +00:00
#include "UI/MenuScreens.h"
#include "UI/EmuScreen.h"
#include "UI/GameInfoCache.h"
2012-11-01 15:19:01 +00:00
2013-03-29 20:21:27 +00:00
EmuScreen::EmuScreen(const std::string &filename) : invalid_(true) {
CheckGLExtensions();
2012-11-01 15:19:01 +00:00
std::string fileToStart = filename;
// This is probably where we should start up the emulated PSP.
INFO_LOG(BOOT, "Starting up hardware.");
CoreParameter coreParam;
coreParam.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER;
2012-11-01 15:19:01 +00:00
coreParam.gpuCore = GPU_GLES;
coreParam.enableSound = g_Config.bEnableSound;
coreParam.fileToStart = fileToStart;
coreParam.mountIso = "";
coreParam.startPaused = false;
coreParam.enableDebugging = false;
coreParam.printfEmuLog = false;
coreParam.headLess = false;
2013-03-29 18:32:20 +00:00
#ifndef _WIN32
if (g_Config.iWindowZoom < 1 || g_Config.iWindowZoom > 2)
g_Config.iWindowZoom = 1;
2013-03-29 18:32:20 +00:00
#endif
coreParam.renderWidth = 480 * g_Config.iWindowZoom;
coreParam.renderHeight = 272 * g_Config.iWindowZoom;
2012-11-19 20:23:29 +00:00
coreParam.outputWidth = dp_xres;
coreParam.outputHeight = dp_yres;
coreParam.pixelWidth = pixel_xres;
coreParam.pixelHeight = pixel_yres;
coreParam.useMediaEngine = false;
2013-04-11 19:04:02 +00:00
if (g_Config.SSAntiAliasing) {
coreParam.renderWidth *= 2;
coreParam.renderHeight *= 2;
}
2012-11-01 15:19:01 +00:00
std::string error_string;
if (PSP_Init(coreParam, &error_string)) {
invalid_ = false;
} else {
invalid_ = true;
errorMessage_ = error_string;
ERROR_LOG(BOOT, "%s", errorMessage_.c_str());
return;
}
globalUIState = UISTATE_INGAME;
host->BootDone();
host->UpdateDisassembly();
2012-11-01 15:19:01 +00:00
LayoutGamepad(dp_xres, dp_yres);
g_gameInfoCache.FlushBGs();
2012-11-01 15:19:01 +00:00
NOTICE_LOG(BOOT, "Loading %s...", fileToStart.c_str());
}
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();
}
}
void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) {
if (result == DR_OK) {
screenManager()->switchScreen(new MenuScreen());
}
}
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")) {
screenManager()->push(new PauseScreen());
} else if (!strcmp(message, "stop")) {
screenManager()->switchScreen(new MenuScreen());
} else if (!strcmp(message, "reset")) {
PSP_Shutdown();
std::string resetError;
if (!PSP_Init(PSP_CoreParameter(), &resetError)) {
2013-03-29 20:21:27 +00:00
ELOG("Error resetting: %s", resetError.c_str());
screenManager()->switchScreen(new MenuScreen());
return;
}
host->BootDone();
host->UpdateDisassembly();
#ifdef _WIN32
if (g_Config.bAutoRun) {
Core_EnableStepping(false);
} else {
Core_EnableStepping(true);
}
#endif
2013-03-29 17:50:08 +00:00
}
}
inline float curve1(float x) {
const float deadzone = 0.15f;
const float factor = 1.0f / (1.0f - deadzone);
if (x > deadzone) {
return (x - deadzone) * (x - deadzone) * factor;
} else if (x < -0.1f) {
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;
}
2013-03-29 20:21:27 +00:00
void EmuScreen::update(InputState &input) {
2013-03-29 18:32:20 +00:00
globalUIState = UISTATE_INGAME;
2012-11-01 15:19:01 +00:00
if (errorMessage_.size()) {
screenManager()->push(new ErrorScreen(
"Error loading file",
errorMessage_));
errorMessage_ = "";
return;
}
if (invalid_)
return;
2012-12-26 07:51:03 +00:00
// First translate touches into native pad input.
// Do this no matter the value of g_Config.bShowTouchControls, some people
// like to use invisible controls...
UpdateGamepad(input);
2013-03-30 23:25:10 +00:00
2012-11-01 15:19:01 +00:00
UpdateInputState(&input);
// Then translate pad input into PSP pad input. Also, add in tilt.
2012-11-01 15:19:01 +00:00
static const int mapping[12][2] = {
{PAD_BUTTON_A, CTRL_CROSS},
2012-12-26 07:51:03 +00:00
{PAD_BUTTON_B, CTRL_CIRCLE},
{PAD_BUTTON_X, CTRL_SQUARE},
2012-11-01 15:19:01 +00:00
{PAD_BUTTON_Y, CTRL_TRIANGLE},
{PAD_BUTTON_UP, CTRL_UP},
{PAD_BUTTON_DOWN, CTRL_DOWN},
{PAD_BUTTON_LEFT, CTRL_LEFT},
{PAD_BUTTON_RIGHT, CTRL_RIGHT},
{PAD_BUTTON_LBUMPER, CTRL_LTRIGGER},
{PAD_BUTTON_RBUMPER, CTRL_RTRIGGER},
{PAD_BUTTON_START, CTRL_START},
2012-12-26 07:51:03 +00:00
{PAD_BUTTON_SELECT, CTRL_SELECT},
2012-11-01 15:19:01 +00:00
};
for (int i = 0; i < 12; i++) {
2012-12-26 07:51:03 +00:00
if (input.pad_buttons_down & mapping[i][0]) {
2012-11-01 15:19:01 +00:00
__CtrlButtonDown(mapping[i][1]);
2012-12-26 07:51:03 +00:00
}
if (input.pad_buttons_up & mapping[i][0]) {
2012-11-01 15:19:01 +00:00
__CtrlButtonUp(mapping[i][1]);
2012-12-26 07:51:03 +00:00
}
2012-11-01 15:19:01 +00:00
}
float stick_x = input.pad_lstick_x;
float stick_y = input.pad_lstick_y;
// Apply tilt
if (g_Config.bAccelerometerToAnalogHoriz) {
// TODO: Deadzone, etc.
stick_x += clamp1(curve1(input.acc.y) * 2.0f);
stick_x = clamp1(stick_x);
}
__CtrlSetAnalog(stick_x, stick_y);
2012-11-01 15:19:01 +00:00
if (input.pad_buttons & PAD_BUTTON_LEFT_THUMB) {
PSP_CoreParameter().unthrottle = true;
} else {
PSP_CoreParameter().unthrottle = false;
}
if (input.pad_buttons_down & (PAD_BUTTON_MENU | PAD_BUTTON_BACK | PAD_BUTTON_RIGHT_THUMB)) {
if (g_Config.bBufferedRendering)
fbo_unbind();
2013-03-29 17:50:08 +00:00
screenManager()->push(new PauseScreen());
2012-11-01 15:19:01 +00:00
}
}
2013-03-29 20:21:27 +00:00
void EmuScreen::render() {
2012-11-01 15:19:01 +00:00
if (invalid_)
return;
2012-11-25 16:21:23 +00:00
// Reapply the graphics state of the PSP
ReapplyGfxState();
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.
// The actual number of cycles doesn't matter so much here as we will break due to CORE_NEXTFRAME, most of the time hopefully...
int blockTicks = usToCycles(1000000 / 10);
// Run until CORE_NEXTFRAME
while (coreState == CORE_RUNNING) {
u64 nowTicks = CoreTiming::GetTicks();
mipsr4k.RunLoopUntil(nowTicks + blockTicks);
}
// Hopefully coreState is now CORE_NEXTFRAME
if (coreState == CORE_NEXTFRAME) {
// set back to running for the next frame
coreState = CORE_RUNNING;
} else if (coreState == CORE_POWERDOWN) {
ILOG("SELF-POWERDOWN!");
screenManager()->switchScreen(new MenuScreen());
}
2012-11-01 15:19:01 +00:00
if (invalid_)
return;
if (g_Config.bBufferedRendering)
fbo_unbind();
2012-11-01 15:19:01 +00:00
UIShader_Prepare();
2012-11-01 15:19:01 +00:00
uiTexture->Bind(0);
2012-11-01 15:19:01 +00:00
glstate.viewport.set(0, 0, pixel_xres, pixel_yres);
glstate.viewport.restore();
ui_draw2d.Begin(UIShader_Get(), DBMODE_NORMAL);
2012-12-01 22:20:08 +00:00
if (g_Config.bShowTouchControls)
DrawGamepad(ui_draw2d);
2012-11-01 15:19:01 +00:00
DrawWatermark();
2012-11-01 15:19:01 +00:00
if (g_Config.bShowDebugStats) {
char statbuf[4096] = {0};
__DisplayGetDebugStats(statbuf);
if (statbuf[4095])
ERROR_LOG(HLE, "Statbuf too big");
ui_draw2d.SetFontScale(.7f, .7f);
ui_draw2d.DrawText(UBUNTU24, statbuf, 11, 11, 0xc0000000);
ui_draw2d.DrawText(UBUNTU24, statbuf, 10, 10, 0xFFFFFFFF);
ui_draw2d.SetFontScale(1.0f, 1.0f);
}
if (g_Config.bShowFPSCounter) {
float vps, fps;
__DisplayGetFPS(&vps, &fps);
char fpsbuf[256];
sprintf(fpsbuf, "VPS: %0.1f", vps);
ui_draw2d.DrawText(UBUNTU24, fpsbuf, dp_xres - 8, 12, 0xc0000000, ALIGN_TOPRIGHT);
ui_draw2d.DrawText(UBUNTU24, fpsbuf, dp_xres - 10, 10, 0xFF3fFF3f, ALIGN_TOPRIGHT);
}
glsl_bind(UIShader_Get());
ui_draw2d.End();
ui_draw2d.Flush();
2012-11-01 15:19:01 +00:00
// Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it?
#if defined(USING_GLES2)
2013-04-11 19:04:02 +00:00
bool hasDiscard = gl_extensions.EXT_discard_framebuffer; // TODO
2012-11-01 15:19:01 +00:00
if (hasDiscard) {
2013-04-11 19:04:02 +00:00
//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
}
2013-03-29 20:21:27 +00:00
void EmuScreen::deviceLost() {
ILOG("EmuScreen::deviceLost()");
2012-12-25 14:28:34 +00:00
gpu->DeviceLost();
2012-11-01 15:19:01 +00:00
}