Merge branch 'master' into TemporaryHackishBranch

# Conflicts:
#	UI/GameSettingsScreen.cpp
#	assets/compat.ini
This commit is contained in:
LunaMoo committed 2019-02-21 03:02:42 +01:00
commit 1bf74bd58c
25 files changed
+749 -330

No files matched your search

+3
View File
@@ -44,6 +44,7 @@ struct DefMappingStruct {
};
KeyMapping g_controllerMap;
int g_controllerMapGeneration = 0;
std::set<std::string> g_seenPads;
bool g_swapped_keys = false;
@@ -837,6 +838,7 @@ void SetKeyMapping(int btn, KeyDef key, bool replace) {
}
g_controllerMap[btn].push_back(key);
}
g_controllerMapGeneration++;
UpdateNativeMenuKeys();
}
@@ -960,6 +962,7 @@ void AutoConfForPad(const std::string &name) {
// Add a couple of convenient keyboard mappings by default, too.
g_controllerMap[VIRTKEY_PAUSE].push_back(KeyDef(DEVICE_ID_KEYBOARD, NKCODE_ESCAPE));
g_controllerMap[VIRTKEY_UNTHROTTLE].push_back(KeyDef(DEVICE_ID_KEYBOARD, NKCODE_TAB));
g_controllerMapGeneration++;
#endif
}
+1
View File
@@ -83,6 +83,7 @@ class IniFile;
namespace KeyMap {
extern KeyMapping g_controllerMap;
extern int g_controllerMapGeneration;
// Key & Button names
struct KeyMap_IntStrPair {
-4
View File
@@ -511,10 +511,6 @@ static int DefaultZoomType() {
return (int)SmallDisplayZoom::AUTO;
}
static bool DefaultTimerHack() {
return false;
}
static int DefaultAndroidHwScale() {
#ifdef __ANDROID__
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19 || System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_TV) {
+2 -2
View File
@@ -207,8 +207,8 @@ void PSPMsgDialog::DisplayMessage(std::string text, bool hasYesNo, bool hasOK)
ey = y2 + 25.0f;
}
PPGeDrawTextWrapped(text.c_str(), 241.0f, y+2, WRAP_WIDTH, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000));
PPGeDrawTextWrapped(text.c_str(), 240.0f, y, WRAP_WIDTH, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0xFFFFFFFF));
PPGeDrawTextWrapped(text.c_str(), 241.0f, y+2, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000));
PPGeDrawTextWrapped(text.c_str(), 240.0f, y, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0xFFFFFFFF));
sy = 125.0f - h2;
PPGeDrawRect(40.0f, sy, 440.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawRect(40.0f, ey, 440.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF));
+1 -1
View File
@@ -81,7 +81,7 @@ int PSPNetconfDialog::Update(int animSpeed) {
StartDraw();
DrawBanner();
PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0x63636363));
PPGeDrawTextWrapped(err->T("PPSSPPDoesNotSupportInternet", "PPSSPP currently does not support connecting to the Internet for DLC, PSN, or game updates."), 241, 132, WRAP_WIDTH, PPGE_ALIGN_CENTER, 0.5f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawTextWrapped(err->T("PPSSPPDoesNotSupportInternet", "PPSSPP currently does not support connecting to the Internet for DLC, PSN, or game updates."), 241, 132, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, 0.5f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawImage(confirmBtnImage, 195, 250, 20, 20, 0, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(di->T("OK"), 225, 252, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
+4 -4
View File
@@ -458,8 +458,8 @@ void PSPSaveDialog::DisplaySaveDataInfo1()
PPGeDrawText(timeTxt.c_str(), 180, 137, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(saveTitleTxt.c_str(), 176, 162, PPGE_ALIGN_LEFT, 0.55f, CalcFadedColor(0x80000000));
PPGeDrawText(saveTitleTxt.c_str(), 175, 159, PPGE_ALIGN_LEFT, 0.55f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(saveDetailTxt.c_str(), 176, 183, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0x80000000));
PPGeDrawText(saveDetailTxt.c_str(), 175, 181, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawTextWrapped(saveDetailTxt.c_str(), 176, 183, 480 - 175, 250 - 183, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0x80000000));
PPGeDrawTextWrapped(saveDetailTxt.c_str(), 175, 181, 480 - 175, 250 - 181, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
}
}
@@ -573,8 +573,8 @@ void PSPSaveDialog::DisplayMessage(std::string text, bool hasYesNo)
yesnoChoice = 0;
}
}
PPGeDrawTextWrapped(text.c_str(), 335.0f, y+2, WRAP_WIDTH, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000));
PPGeDrawTextWrapped(text.c_str(), 334.0f, y, WRAP_WIDTH, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0xFFFFFFFF));
PPGeDrawTextWrapped(text.c_str(), 335.0f, y+2, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000));
PPGeDrawTextWrapped(text.c_str(), 334.0f, y, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0xFFFFFFFF));
float sy = 122.0f - h2, ey = 150.0f + h2;
PPGeDrawRect(202.0f, sy, 466.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawRect(202.0f, ey, 466.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF));
+5
View File
@@ -180,6 +180,11 @@ void __DisplayFlip(int cyclesLate);
static void ScheduleLagSync(int over = 0) {
lagSyncScheduled = g_Config.bForceLagSync;
if (lagSyncScheduled) {
// Reset over if it became too high, such as after pausing or initial loading.
// There's no real sense in it being more than 1/60th of a second.
if (over > 1000000 / 60) {
over = 0;
}
CoreTiming::ScheduleEvent(usToCycles(1000 + over), lagSyncEvent, 0);
lastLagSync = real_time_now();
}
+64 -13
View File
@@ -17,6 +17,7 @@
#include <algorithm>
#include "base/stringutil.h"
#include "image/zim_load.h"
#include "image/png_load.h"
#include "util/text/utf8.h"
@@ -377,7 +378,7 @@ static const AtlasChar *PPGeGetChar(const AtlasFont &atlasfont, unsigned int cva
// Break a single text string into mutiple lines.
static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont, float x, float y,
int align, float scale, int wrapType, float wrapWidth, bool dryRun)
int align, float scale, float lineHeightScale, int wrapType, float wrapWidth, bool dryRun)
{
y += atlasfont.ascend * scale;
float sx = x, sy = y;
@@ -399,7 +400,7 @@ static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont,
int numLines = 1;
float maxw = 0;
float lineHeight = atlasfont.height * scale;
float lineHeight = atlasfont.height * lineHeightScale;
for (UTF8 utf(text); !utf.end(); )
{
float lineWidth = 0;
@@ -617,16 +618,16 @@ void PPGeMeasureText(float *w, float *h, int *n,
const char *text, float scale, int WrapType, int wrapWidth)
{
const AtlasFont &atlasfont = *ppge_atlas.fonts[0];
AtlasTextMetrics metrics = BreakLines(text, atlasfont, 0, 0, 0, scale, WrapType, wrapWidth, true);
AtlasTextMetrics metrics = BreakLines(text, atlasfont, 0, 0, 0, scale, scale, WrapType, wrapWidth, true);
if (w) *w = metrics.maxWidth;
if (h) *h = metrics.lineHeight;
if (n) *n = metrics.numLines;
}
void PPGePrepareText(const char *text, float x, float y, int align, float scale, int WrapType, int wrapWidth)
void PPGePrepareText(const char *text, float x, float y, int align, float scale, float lineHeightScale, int WrapType, int wrapWidth)
{
const AtlasFont &atlasfont = *ppge_atlas.fonts[0];
char_lines_metrics = BreakLines(text, atlasfont, x, y, align, scale, WrapType, wrapWidth, false);
char_lines_metrics = BreakLines(text, atlasfont, x, y, align, scale, lineHeightScale, WrapType, wrapWidth, false);
}
void PPGeMeasureCurrentText(float *x, float *y, float *w, float *h, int *n)
@@ -638,6 +639,13 @@ void PPGeMeasureCurrentText(float *x, float *y, float *w, float *h, int *n)
if (n) *n = char_lines_metrics.numLines;
}
static void PPGeResetCurrentText() {
char_one_line.clear();
char_lines.clear();
AtlasTextMetrics zeroBox = { 0 };
char_lines_metrics = zeroBox;
}
// Draws some text using the one font we have.
// Mostly rewritten.
void PPGeDrawCurrentText(u32 color)
@@ -661,21 +669,64 @@ void PPGeDrawCurrentText(u32 color)
}
EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
}
char_one_line.clear();
char_lines.clear();
AtlasTextMetrics zeroBox = { 0 };
char_lines_metrics = zeroBox;
PPGeResetCurrentText();
}
void PPGeDrawText(const char *text, float x, float y, int align, float scale, u32 color)
{
PPGePrepareText(text, x, y, align, scale, PPGE_LINE_USE_ELLIPSIS);
PPGePrepareText(text, x, y, align, scale, scale, PPGE_LINE_USE_ELLIPSIS);
PPGeDrawCurrentText(color);
}
void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, int align, float scale, u32 color)
{
PPGePrepareText(text, x, y, align, scale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth);
static std::string StripTrailingWhite(const std::string &s) {
size_t lastChar = s.find_last_not_of(" \t\r\n");
if (lastChar != s.npos) {
return s.substr(0, lastChar + 1);
}
return s;
}
static std::string CropLinesToCount(const std::string &s, int numLines) {
std::vector<std::string> lines;
SplitString(s, '\n', lines);
if ((int)lines.size() <= numLines) {
return s;
}
size_t len = 0;
for (int i = 0; i < numLines; ++i) {
len += lines[i].length() + 1;
}
return s.substr(0, len);
}
void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, float wrapHeight, int align, float scale, u32 color) {
std::string s = text;
if (wrapHeight != 0.0f) {
s = StripTrailingWhite(s);
}
PPGePrepareText(s.c_str(), x, y, align, scale, scale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth);
int zoom = (PSP_CoreParameter().pixelHeight + 479) / 480;
float maxScaleDown = zoom == 1 ? 1.3f : 2.0f;
float actualHeight = char_lines_metrics.lineHeight * char_lines_metrics.numLines;
if (wrapHeight != 0.0f && actualHeight > wrapHeight) {
if (actualHeight > wrapHeight * maxScaleDown) {
float maxLines = floor(wrapHeight * maxScaleDown / char_lines_metrics.lineHeight);
actualHeight = (maxLines + 1) * char_lines_metrics.lineHeight;
// Add an ellipsis if it's just too long to be readable.
// On a PSP, it does this without scaling it down.
s = StripTrailingWhite(CropLinesToCount(s, (int)maxLines)) + "\n...";
}
// Measure the text again after scaling down.
PPGeResetCurrentText();
float reduced = scale * wrapHeight / actualHeight;
// Try to keep the font as large as possible, so reduce the line height some.
PPGePrepareText(s.c_str(), x, y, align, reduced * 1.15, reduced, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth);
}
PPGeDrawCurrentText(color);
}
+2 -2
View File
@@ -80,7 +80,7 @@ void PPGeMeasureText(float *w, float *h, int *n,
const char *text, float scale, int WrapType = PPGE_LINE_NONE, int wrapWidth = 0);
// Overwrite the current text lines buffer so it can be drawn later.
void PPGePrepareText(const char *text, float x, float y, int align, float scale,
void PPGePrepareText(const char *text, float x, float y, int align, float scale, float lineHeightScale,
int WrapType = PPGE_LINE_NONE, int wrapWidth = 0);
// Get the metrics of the bounding box of the currently stated text.
@@ -95,7 +95,7 @@ void PPGeDrawCurrentText(u32 color = 0xFFFFFFFF);
// Draws some text using the one font we have.
// Clears the text buffer when done.
void PPGeDrawText(const char *text, float x, float y, int align, float scale = 1.0f, u32 color = 0xFFFFFFFF);
void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, int align, float scale = 1.0f, u32 color = 0xFFFFFFFF);
void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, float wrapHeight, int align, float scale = 1.0f, u32 color = 0xFFFFFFFF);
// Draws a "4-patch" for button-like things that can be resized.
void PPGeDraw4Patch(int atlasImage, float x, float y, float w, float h, u32 color = 0xFFFFFFFF);
+6 -6
View File
@@ -11,7 +11,7 @@
#include "GPU/Common/ShaderId.h"
#include "GPU/Common/VertexDecoderCommon.h"
std::string VertexShaderDesc(const ShaderID &id) {
std::string VertexShaderDesc(const VShaderID &id) {
std::stringstream desc;
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR ";
@@ -60,7 +60,7 @@ std::string VertexShaderDesc(const ShaderID &id) {
return desc.str();
}
void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) {
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform) {
bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doTextureTransform = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
@@ -81,7 +81,7 @@ void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform)
bool enableFog = gstate.isFogEnabled() && !isModeThrough && !gstate.isModeClear();
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
ShaderID id;
VShaderID id;
id.SetBit(VS_BIT_LMODE, lmode);
id.SetBit(VS_BIT_IS_THROUGH, isModeThrough);
id.SetBit(VS_BIT_ENABLE_FOG, enableFog);
@@ -160,7 +160,7 @@ static bool MatrixNeedsProjection(const float m[12]) {
return m[2] != 0.0f || m[5] != 0.0f || m[8] != 0.0f || m[11] != 1.0f;
}
std::string FragmentShaderDesc(const ShaderID &id) {
std::string FragmentShaderDesc(const FShaderID &id) {
std::stringstream desc;
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
if (id.Bit(FS_BIT_CLEARMODE)) desc << "Clear ";
@@ -226,8 +226,8 @@ std::string FragmentShaderDesc(const ShaderID &id) {
// Here we must take all the bits of the gstate that determine what the fragment shader will
// look like, and concatenate them together into an ID.
void ComputeFragmentShaderID(ShaderID *id_out, const Draw::Bugs &bugs) {
ShaderID id;
void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) {
FShaderID id;
if (gstate.isModeClear()) {
// We only need one clear shader, so let's ignore the rest of the bits.
id.SetBit(FS_BIT_CLEARMODE);
+59 -17
View File
@@ -8,7 +8,7 @@
// TODO: There will be additional bits, indicating that groups of these will be
// sent to the shader and processed there. This will cut down the number of shaders ("ubershader approach")
// This is probably only really worth doing for lighting and bones.
enum {
enum VShaderBit : uint8_t {
VS_BIT_LMODE = 0,
VS_BIT_IS_THROUGH = 1,
VS_BIT_ENABLE_FOG = 2,
@@ -55,9 +55,12 @@ enum {
// No more free
};
static inline VShaderBit operator +(VShaderBit bit, int i) {
return VShaderBit((int)bit + i);
}
// Local
enum {
enum FShaderBit : uint8_t {
FS_BIT_CLEARMODE = 0,
FS_BIT_DO_TEXTURE = 1,
FS_BIT_TEXFUNC = 2, // 3 bits
@@ -91,6 +94,10 @@ enum {
// 50+ are free.
};
static inline FShaderBit operator +(FShaderBit bit, int i) {
return FShaderBit((int)bit + i);
}
struct ShaderID {
ShaderID() {
clear();
@@ -126,6 +133,20 @@ struct ShaderID {
bool operator != (const ShaderID &other) const {
return !(*this == other);
}
uint32_t Word(int word) const {
return d[word];
}
void ToString(std::string *dest) const {
dest->resize(sizeof(d));
memcpy(&(*dest)[0], d, sizeof(d));
}
void FromString(std::string src) {
memcpy(d, &(src)[0], sizeof(d));
}
protected:
bool Bit(int bit) const {
return (d[bit >> 5] >> (bit & 31)) & 1;
}
@@ -134,9 +155,6 @@ struct ShaderID {
const int mask = (1 << count) - 1;
return (d[bit >> 5] >> (bit & 31)) & mask;
}
uint32_t Word(int word) const {
return d[word];
}
void SetBit(int bit, bool value = true) {
if (value) {
d[bit >> 5] |= 1 << (bit & 31);
@@ -148,14 +166,6 @@ struct ShaderID {
d[bit >> 5] |= (value & mask) << (bit & 31);
}
}
void ToString(std::string *dest) const {
dest->resize(sizeof(d));
memcpy(&(*dest)[0], d, sizeof(d));
}
void FromString(std::string src) {
memcpy(d, &(src)[0], sizeof(d));
}
};
struct VShaderID : ShaderID {
@@ -165,6 +175,22 @@ struct VShaderID : ShaderID {
explicit VShaderID(ShaderID &src) {
memcpy(d, src.d, sizeof(d));
}
bool Bit(VShaderBit bit) const {
return ShaderID::Bit((int)bit);
}
int Bits(VShaderBit bit, int count) const {
return ShaderID::Bits((int)bit, count);
}
void SetBit(VShaderBit bit, bool value = true) {
ShaderID::SetBit((int)bit, value);
}
void SetBits(VShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
};
struct FShaderID : ShaderID {
@@ -174,6 +200,22 @@ struct FShaderID : ShaderID {
explicit FShaderID(ShaderID &src) {
memcpy(d, src.d, sizeof(d));
}
bool Bit(FShaderBit bit) const {
return ShaderID::Bit((int)bit);
}
int Bits(FShaderBit bit, int count) const {
return ShaderID::Bits((int)bit, count);
}
void SetBit(FShaderBit bit, bool value = true) {
ShaderID::SetBit((int)bit, value);
}
void SetBits(FShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
};
namespace Draw {
@@ -181,10 +223,10 @@ class Bugs;
}
void ComputeVertexShaderID(ShaderID *id, uint32_t vertexType, bool useHWTransform);
void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform);
// Generates a compact string that describes the shader. Useful in a list to get an overview
// of the current flora of shaders.
std::string VertexShaderDesc(const ShaderID &id);
std::string VertexShaderDesc(const VShaderID &id);
void ComputeFragmentShaderID(ShaderID *id, const Draw::Bugs &bugs);
std::string FragmentShaderDesc(const ShaderID &id);
void ComputeFragmentShaderID(FShaderID *id, const Draw::Bugs &bugs);
std::string FragmentShaderDesc(const FShaderID &id);
+1 -1
View File
@@ -762,7 +762,7 @@ std::string Shader::GetShaderString(DebugShaderStringType type, ShaderID id) con
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return isFragment_ ? FragmentShaderDesc(id) : VertexShaderDesc(id);
return isFragment_ ? FragmentShaderDesc(FShaderID(id)) : VertexShaderDesc(VShaderID(id));
default:
return "N/A";
}
+207 -184
View File
@@ -6,13 +6,15 @@
// Currently supports: Android, Linux, Windows, Mac OSX
#include <QApplication>
#include <QUrl>
#include <QDir>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QLocale>
#include <QScreen>
#include <QThread>
#include <QUrl>
#include "ext/glslang/glslang/Public/ShaderLang.h"
@@ -29,6 +31,7 @@
#endif
#include "QtMain.h"
#include "gfx_es2/gpu_features.h"
#include "i18n/i18n.h"
#include "math/math_util.h"
#include "thread/threadutil.h"
#include "util/text/utf8.h"
@@ -37,8 +40,10 @@
#include <string.h>
MainUI *emugl = NULL;
MainUI *emugl = nullptr;
static int refreshRate = 60000;
static int browseFileEvent = -1;
static int browseFolderEvent = -1;
#ifdef SDL
extern void mixaudio(void *userdata, Uint8 *stream, int len) {
@@ -94,6 +99,8 @@ bool System_GetPropertyBool(SystemProperty prop) {
switch (prop) {
case SYSPROP_HAS_BACK_BUTTON:
return true;
case SYSPROP_HAS_FILE_BROWSER:
return true;
case SYSPROP_APP_GOLD:
#ifdef GOLD
return true;
@@ -108,6 +115,10 @@ bool System_GetPropertyBool(SystemProperty prop) {
void System_SendMessage(const char *command, const char *parameter) {
if (!strcmp(command, "finish")) {
qApp->exit(0);
} else if (!strcmp(command, "browse_file")) {
QCoreApplication::postEvent(emugl, new QEvent((QEvent::Type)browseFileEvent));
} else if (!strcmp(command, "browse_folder")) {
QCoreApplication::postEvent(emugl, new QEvent((QEvent::Type)browseFolderEvent));
}
}
@@ -190,6 +201,10 @@ static int mainInternal(QApplication &a) {
QScopedPointer<MainAudio> audio(new MainAudio());
audio->run();
#endif
browseFileEvent = QEvent::registerEventType();
browseFolderEvent = QEvent::registerEventType();
int retval = a.exec();
delete emugl;
return retval;
@@ -227,9 +242,8 @@ void MainUI::EmuThreadJoin() {
emuThread = std::thread();
}
MainUI::MainUI(QWidget *parent):
QGLWidget(parent)
{
MainUI::MainUI(QWidget *parent)
: QGLWidget(parent) {
emuThreadState = (int)EmuThreadState::DISABLED;
setAttribute(Qt::WA_AcceptTouchEvents);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
@@ -244,8 +258,7 @@ MainUI::MainUI(QWidget *parent):
startTimer(16);
}
MainUI::~MainUI()
{
MainUI::~MainUI() {
ILOG("MainUI::Destructor");
if (emuThreadState != (int)EmuThreadState::DISABLED) {
ILOG("EmuThreadStop");
@@ -264,134 +277,148 @@ MainUI::~MainUI()
graphicsContext = nullptr;
}
QString MainUI::InputBoxGetQString(QString title, QString defaultValue)
{
bool ok;
QString text = QInputDialog::getText(this, title, title, QLineEdit::Normal, defaultValue, &ok);
if (!ok)
text = QString();
return text;
QString MainUI::InputBoxGetQString(QString title, QString defaultValue) {
bool ok;
QString text = QInputDialog::getText(this, title, title, QLineEdit::Normal, defaultValue, &ok);
if (!ok)
text = QString();
return text;
}
void MainUI::resizeGL(int w, int h)
{
if (UpdateScreenScale(w, h)) {
NativeMessageReceived("gpu_resized", "");
}
xscale = w / this->width();
yscale = h / this->height();
void MainUI::resizeGL(int w, int h) {
if (UpdateScreenScale(w, h)) {
NativeMessageReceived("gpu_resized", "");
}
xscale = w / this->width();
yscale = h / this->height();
PSP_CoreParameter().pixelWidth = pixel_xres;
PSP_CoreParameter().pixelHeight = pixel_yres;
PSP_CoreParameter().pixelWidth = pixel_xres;
PSP_CoreParameter().pixelHeight = pixel_yres;
}
void MainUI::timerEvent(QTimerEvent *)
{
updateGL();
emit newFrame();
void MainUI::timerEvent(QTimerEvent *) {
updateGL();
emit newFrame();
}
void MainUI::changeEvent(QEvent *e)
{
QGLWidget::changeEvent(e);
if(e->type() == QEvent::WindowStateChange)
Core_NotifyWindowHidden(isMinimized());
void MainUI::changeEvent(QEvent *e) {
QGLWidget::changeEvent(e);
if (e->type() == QEvent::WindowStateChange)
Core_NotifyWindowHidden(isMinimized());
}
bool MainUI::event(QEvent *e)
{
TouchInput input;
QList<QTouchEvent::TouchPoint> touchPoints;
switch(e->type())
{
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
touchPoints = static_cast<QTouchEvent *>(e)->touchPoints();
foreach (const QTouchEvent::TouchPoint &touchPoint, touchPoints) {
switch (touchPoint.state()) {
case Qt::TouchPointStationary:
break;
case Qt::TouchPointPressed:
case Qt::TouchPointReleased:
input.x = touchPoint.pos().x() * g_dpi_scale_x * xscale;
input.y = touchPoint.pos().y() * g_dpi_scale_y * yscale;
input.flags = (touchPoint.state() == Qt::TouchPointPressed) ? TOUCH_DOWN : TOUCH_UP;
input.id = touchPoint.id();
NativeTouch(input);
break;
case Qt::TouchPointMoved:
input.x = touchPoint.pos().x() * g_dpi_scale_x * xscale;
input.y = touchPoint.pos().y() * g_dpi_scale_y * yscale;
input.flags = TOUCH_MOVE;
input.id = touchPoint.id();
NativeTouch(input);
break;
default:
break;
}
}
break;
case QEvent::MouseButtonDblClick:
if (!g_Config.bShowTouchControls || GetUIState() != UISTATE_INGAME)
emit doubleClick();
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
input.x = ((QMouseEvent*)e)->pos().x() * g_dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_dpi_scale_y * yscale;
input.flags = (e->type() == QEvent::MouseButtonPress) ? TOUCH_DOWN : TOUCH_UP;
input.id = 0;
NativeTouch(input);
break;
case QEvent::MouseMove:
input.x = ((QMouseEvent*)e)->pos().x() * g_dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_dpi_scale_y * yscale;
input.flags = TOUCH_MOVE;
input.id = 0;
NativeTouch(input);
break;
case QEvent::Wheel:
NativeKey(KeyInput(DEVICE_ID_MOUSE, ((QWheelEvent*)e)->delta()<0 ? NKCODE_EXT_MOUSEWHEEL_DOWN : NKCODE_EXT_MOUSEWHEEL_UP, KEY_DOWN));
break;
case QEvent::KeyPress:
{
auto qtKeycode = ((QKeyEvent*)e)->key();
auto iter = KeyMapRawQttoNative.find(qtKeycode);
int nativeKeycode = 0;
if (iter != KeyMapRawQttoNative.end()) {
nativeKeycode = iter->second;
NativeKey(KeyInput(DEVICE_ID_KEYBOARD, nativeKeycode, KEY_DOWN));
}
bool MainUI::event(QEvent *e) {
TouchInput input;
QList<QTouchEvent::TouchPoint> touchPoints;
// Also get the unicode value.
QString text = ((QKeyEvent*)e)->text();
std::string str = text.toStdString();
// Now, we don't want CHAR events for non-printable characters. Not quite sure how we'll best
// do that, but here's one attempt....
switch (nativeKeycode) {
case NKCODE_DEL:
case NKCODE_FORWARD_DEL:
case NKCODE_TAB:
break;
default:
if (str.size()) {
int pos = 0;
int code = u8_nextchar(str.c_str(), &pos);
NativeKey(KeyInput(DEVICE_ID_KEYBOARD, code, KEY_CHAR));
}
break;
}
switch (e->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
touchPoints = static_cast<QTouchEvent *>(e)->touchPoints();
foreach (const QTouchEvent::TouchPoint &touchPoint, touchPoints) {
switch (touchPoint.state()) {
case Qt::TouchPointStationary:
break;
case Qt::TouchPointPressed:
case Qt::TouchPointReleased:
input.x = touchPoint.pos().x() * g_dpi_scale_x * xscale;
input.y = touchPoint.pos().y() * g_dpi_scale_y * yscale;
input.flags = (touchPoint.state() == Qt::TouchPointPressed) ? TOUCH_DOWN : TOUCH_UP;
input.id = touchPoint.id();
NativeTouch(input);
break;
case Qt::TouchPointMoved:
input.x = touchPoint.pos().x() * g_dpi_scale_x * xscale;
input.y = touchPoint.pos().y() * g_dpi_scale_y * yscale;
input.flags = TOUCH_MOVE;
input.id = touchPoint.id();
NativeTouch(input);
break;
default:
break;
}
}
break;
case QEvent::MouseButtonDblClick:
if (!g_Config.bShowTouchControls || GetUIState() != UISTATE_INGAME)
emit doubleClick();
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
input.x = ((QMouseEvent*)e)->pos().x() * g_dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_dpi_scale_y * yscale;
input.flags = (e->type() == QEvent::MouseButtonPress) ? TOUCH_DOWN : TOUCH_UP;
input.id = 0;
NativeTouch(input);
break;
case QEvent::MouseMove:
input.x = ((QMouseEvent*)e)->pos().x() * g_dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_dpi_scale_y * yscale;
input.flags = TOUCH_MOVE;
input.id = 0;
NativeTouch(input);
break;
case QEvent::Wheel:
NativeKey(KeyInput(DEVICE_ID_MOUSE, ((QWheelEvent*)e)->delta()<0 ? NKCODE_EXT_MOUSEWHEEL_DOWN : NKCODE_EXT_MOUSEWHEEL_UP, KEY_DOWN));
break;
case QEvent::KeyPress:
{
auto qtKeycode = ((QKeyEvent*)e)->key();
auto iter = KeyMapRawQttoNative.find(qtKeycode);
int nativeKeycode = 0;
if (iter != KeyMapRawQttoNative.end()) {
nativeKeycode = iter->second;
NativeKey(KeyInput(DEVICE_ID_KEYBOARD, nativeKeycode, KEY_DOWN));
}
// Also get the unicode value.
QString text = ((QKeyEvent*)e)->text();
std::string str = text.toStdString();
// Now, we don't want CHAR events for non-printable characters. Not quite sure how we'll best
// do that, but here's one attempt....
switch (nativeKeycode) {
case NKCODE_DEL:
case NKCODE_FORWARD_DEL:
case NKCODE_TAB:
break;
default:
if (str.size()) {
int pos = 0;
int code = u8_nextchar(str.c_str(), &pos);
NativeKey(KeyInput(DEVICE_ID_KEYBOARD, code, KEY_CHAR));
}
break;
case QEvent::KeyRelease:
NativeKey(KeyInput(DEVICE_ID_KEYBOARD, KeyMapRawQttoNative.find(((QKeyEvent*)e)->key())->second, KEY_UP));
break;
default:
return QWidget::event(e);
}
e->accept();
return true;
break;
}
}
break;
case QEvent::KeyRelease:
NativeKey(KeyInput(DEVICE_ID_KEYBOARD, KeyMapRawQttoNative.find(((QKeyEvent*)e)->key())->second, KEY_UP));
break;
default:
if (e->type() == browseFileEvent) {
QString fileName = QFileDialog::getOpenFileName(nullptr, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf *.zip *.ppdmp)");
if (QFile::exists(fileName)) {
QDir newPath;
g_Config.currentDirectory = newPath.filePath(fileName).toStdString();
g_Config.Save();
NativeMessageReceived("boot", fileName.toStdString().c_str());
}
break;
} else if (e->type() == browseFolderEvent) {
I18NCategory *mm = GetI18NCategory("MainMenu");
QString fileName = QFileDialog::getExistingDirectory(nullptr, mm->T("Choose folder"), g_Config.currentDirectory.c_str());
if (QDir(fileName).exists()) {
NativeMessageReceived("browse_folderSelect", fileName.toStdString().c_str());
}
} else {
return QWidget::event(e);
}
}
e->accept();
return true;
}
void MainUI::initializeGL() {
@@ -425,9 +452,9 @@ void MainUI::initializeGL() {
}
void MainUI::paintGL() {
#ifdef SDL
#ifdef SDL
SDL_PumpEvents();
#endif
#endif
updateAccelerometer();
if (emuThreadState == (int)EmuThreadState::DISABLED) {
UpdateRunLoop();
@@ -437,28 +464,27 @@ void MainUI::paintGL() {
}
}
void MainUI::updateAccelerometer()
{
void MainUI::updateAccelerometer() {
#if defined(MOBILE_DEVICE)
// TODO: Toggle it depending on whether it is enabled
QAccelerometerReading *reading = acc->reading();
if (reading) {
AxisInput axis;
axis.deviceId = DEVICE_ID_ACCELEROMETER;
axis.flags = 0;
// TODO: Toggle it depending on whether it is enabled
QAccelerometerReading *reading = acc->reading();
if (reading) {
AxisInput axis;
axis.deviceId = DEVICE_ID_ACCELEROMETER;
axis.flags = 0;
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_X;
axis.value = reading->x();
NativeAxis(axis);
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_X;
axis.value = reading->x();
NativeAxis(axis);
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_Y;
axis.value = reading->y();
NativeAxis(axis);
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_Y;
axis.value = reading->y();
NativeAxis(axis);
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_Z;
axis.value = reading->z();
NativeAxis(axis);
}
axis.axisId = JOYSTICK_AXIS_ACCELEROMETER_Z;
axis.value = reading->z();
NativeAxis(axis);
}
#endif
}
@@ -470,49 +496,46 @@ void MainUI::updateAccelerometer()
#define AUDIO_SAMPLESIZE 16
#define AUDIO_BUFFERS 5
MainAudio::~MainAudio()
{
if (feed != NULL) {
killTimer(timer);
feed->close();
}
if (output) {
output->stop();
delete output;
}
if (mixbuf)
free(mixbuf);
MainAudio::~MainAudio() {
if (feed != nullptr) {
killTimer(timer);
feed->close();
}
if (output) {
output->stop();
delete output;
}
if (mixbuf)
free(mixbuf);
}
void MainAudio::run()
{
QAudioFormat fmt;
fmt.setSampleRate(AUDIO_FREQ);
fmt.setCodec("audio/pcm");
fmt.setChannelCount(AUDIO_CHANNELS);
fmt.setSampleSize(AUDIO_SAMPLESIZE);
fmt.setByteOrder(QAudioFormat::LittleEndian);
fmt.setSampleType(QAudioFormat::SignedInt);
mixlen = sizeof(short)*AUDIO_BUFFERS*AUDIO_CHANNELS*AUDIO_SAMPLES;
mixbuf = (char*)malloc(mixlen);
output = new QAudioOutput(fmt);
output->setBufferSize(mixlen);
feed = output->start();
if (feed != NULL) {
// buffering has already done in the internal mixed buffer
// use a small interval to copy mixed audio stream from
// internal buffer to audio output buffer as soon as possible
// use 1 instead of 0 to prevent CPU exhausting
timer = startTimer(1);
}
void MainAudio::run() {
QAudioFormat fmt;
fmt.setSampleRate(AUDIO_FREQ);
fmt.setCodec("audio/pcm");
fmt.setChannelCount(AUDIO_CHANNELS);
fmt.setSampleSize(AUDIO_SAMPLESIZE);
fmt.setByteOrder(QAudioFormat::LittleEndian);
fmt.setSampleType(QAudioFormat::SignedInt);
mixlen = sizeof(short)*AUDIO_BUFFERS*AUDIO_CHANNELS*AUDIO_SAMPLES;
mixbuf = (char*)malloc(mixlen);
output = new QAudioOutput(fmt);
output->setBufferSize(mixlen);
feed = output->start();
if (feed != nullptr) {
// buffering has already done in the internal mixed buffer
// use a small interval to copy mixed audio stream from
// internal buffer to audio output buffer as soon as possible
// use 1 instead of 0 to prevent CPU exhausting
timer = startTimer(1);
}
}
void MainAudio::timerEvent(QTimerEvent *)
{
memset(mixbuf, 0, mixlen);
size_t frames = NativeMix((short *)mixbuf, AUDIO_BUFFERS*AUDIO_SAMPLES);
if (frames > 0)
feed->write(mixbuf, sizeof(short) * AUDIO_CHANNELS * frames);
void MainAudio::timerEvent(QTimerEvent *) {
memset(mixbuf, 0, mixlen);
size_t frames = NativeMix((short *)mixbuf, AUDIO_BUFFERS*AUDIO_SAMPLES);
if (frames > 0)
feed->write(mixbuf, sizeof(short) * AUDIO_CHANNELS * frames);
}
#endif
+25 -5
View File
@@ -435,16 +435,18 @@ int main(int argc, char *argv[]) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetSwapInterval(1);
// Is resolution is too low to run windowed
// Force fullscreen if the resolution is too low to run windowed.
if (g_DesktopWidth < 480 * 2 && g_DesktopHeight < 272 * 2) {
mode |= SDL_WINDOW_FULLSCREEN_DESKTOP;
}
// If we're on mobile, don't try for windowed either.
#if defined(MOBILE_DEVICE)
mode |= SDL_WINDOW_FULLSCREEN;
mode |= SDL_WINDOW_FULLSCREEN;
#elif defined(USING_FBDEV)
mode |= SDL_WINDOW_FULLSCREEN_DESKTOP;
#else
mode |= SDL_WINDOW_RESIZABLE;
mode |= SDL_WINDOW_RESIZABLE;
#endif
if (mode & SDL_WINDOW_FULLSCREEN_DESKTOP) {
@@ -600,6 +602,7 @@ int main(int argc, char *argv[]) {
}
graphicsContext->ThreadStart();
bool windowHidden = false;
while (true) {
double startTime = time_now_d();
SDL_Event event, touchEvent;
@@ -636,6 +639,19 @@ int main(int argc, char *argv[]) {
break;
}
case SDL_WINDOWEVENT_MINIMIZED:
case SDL_WINDOWEVENT_HIDDEN:
windowHidden = true;
Core_NotifyWindowHidden(windowHidden);
break;
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
windowHidden = false;
Core_NotifyWindowHidden(windowHidden);
break;
default:
break;
}
@@ -682,6 +698,8 @@ int main(int argc, char *argv[]) {
NativeKey(key);
break;
}
// This behavior doesn't feel right on a macbook with a touchpad.
#if !PPSSPP_PLATFORM(MAC)
case SDL_FINGERMOTION:
{
SDL_GetWindowSize(window, &w, &h);
@@ -744,6 +762,7 @@ int main(int argc, char *argv[]) {
SDL_PushEvent(&touchEvent);
break;
}
#endif
case SDL_MOUSEBUTTONDOWN:
switch (event.button.button) {
case SDL_BUTTON_LEFT:
@@ -847,7 +866,8 @@ int main(int argc, char *argv[]) {
// glsl_refresh(); // auto-reloads modified GLSL shaders once per second.
}
if (emuThreadState != (int)EmuThreadState::DISABLED) {
bool renderThreadPaused = windowHidden && g_Config.bPauseWhenMinimized && emuThreadState != (int)EmuThreadState::DISABLED;
if (emuThreadState != (int)EmuThreadState::DISABLED && !renderThreadPaused) {
if (!graphicsContext->ThreadFrame())
break;
}
@@ -859,7 +879,7 @@ int main(int argc, char *argv[]) {
// Simple throttling to not burn the GPU in the menu.
time_update();
if (GetUIState() != UISTATE_INGAME || !PSP_IsInited()) {
if (GetUIState() != UISTATE_INGAME || !PSP_IsInited() || renderThreadPaused) {
double diffTime = time_now_d() - startTime;
int sleepTime = (int)(1000.0 / 60.0) - (int)(diffTime * 1000.0);
if (sleepTime > 0)
+4
View File
@@ -29,6 +29,7 @@
#include "ui/view.h"
#include "ui/viewgroup.h"
#include "Core/Host.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/System.h"
#include "Common/KeyMap.h"
@@ -79,6 +80,7 @@ void ControlMapper::Update() {
if (refresh_) {
refresh_ = false;
Refresh();
host->UpdateUI();
}
}
@@ -169,6 +171,7 @@ void ControlMapper::MappedCallback(KeyDef kdf) {
break;
case REPLACEONE:
KeyMap::g_controllerMap[pspKey_][actionIndex_] = kdf;
KeyMap::g_controllerMapGeneration++;
break;
default:
;
@@ -211,6 +214,7 @@ UI::EventReturn ControlMapper::OnAddMouse(UI::EventParams &params) {
UI::EventReturn ControlMapper::OnDelete(UI::EventParams &params) {
int index = atoi(params.v->Tag().c_str());
KeyMap::g_controllerMap[pspKey_].erase(KeyMap::g_controllerMap[pspKey_].begin() + index);
KeyMap::g_controllerMapGeneration++;
refresh_ = true;
return UI::EVENT_DONE;
}
+78 -2
View File
@@ -804,7 +804,11 @@ void GameSettingsScreen::CreateViews() {
#if defined(USING_WIN_UI)
systemSettings->Add(new CheckBox(&g_Config.bBypassOSKWithKeyboard, sy->T("Enable Windows native keyboard", "Enable Windows native keyboard")));
#endif
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
#if PPSSPP_PLATFORM(ANDROID)
auto memstickPath = systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.memStickDirectory, sy->T("Change Memory Stick folder"), (const char *)nullptr));
memstickPath->SetEnabled(!PSP_IsInited());
memstickPath->OnClick.Handle(this, &GameSettingsScreen::OnChangeMemStickDir);
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
SavePathInMyDocumentChoice = systemSettings->Add(new CheckBox(&installed_, sy->T("Save path in My Documents", "Save path in My Documents")));
SavePathInMyDocumentChoice->OnClick.Handle(this, &GameSettingsScreen::OnSavePathMydoc);
SavePathInOtherChoice = systemSettings->Add(new CheckBox(&otherinstalled_, sy->T("Save path in installed.txt", "Save path in installed.txt")));
@@ -982,7 +986,15 @@ UI::EventReturn GameSettingsScreen::OnJitAffectingSetting(UI::EventParams &e) {
return UI::EVENT_DONE;
}
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
#if PPSSPP_PLATFORM(ANDROID)
UI::EventReturn GameSettingsScreen::OnChangeMemStickDir(UI::EventParams &e) {
I18NCategory *sy = GetI18NCategory("System");
System_SendMessage("inputbox", (std::string(sy->T("Memory Stick Folder")) + ":" + g_Config.memStickDirectory).c_str());
return UI::EVENT_DONE;
}
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
UI::EventReturn GameSettingsScreen::OnSavePathMydoc(UI::EventParams &e) {
const std::string PPSSPPpath = File::GetExeDirectory();
@@ -1145,6 +1157,70 @@ void GameSettingsScreen::onFinish(DialogResult result) {
NativeMessageReceived("gpu_clearShaderCache", "");
}
void GameSettingsScreen::sendMessage(const char *message, const char *value) {
UIDialogScreenWithGameBackground::sendMessage(message, value);
I18NCategory *sy = GetI18NCategory("System");
I18NCategory *di = GetI18NCategory("Dialog");
if (!strcmp(message, "inputbox_completed")) {
std::vector<std::string> inputboxValue;
SplitString(value, ':', inputboxValue);
#if PPSSPP_PLATFORM(ANDROID)
if (inputboxValue.size() >= 2 && inputboxValue[0] == sy->T("Memory Stick Folder")) {
// Allow colons in the path.
std::string newPath = std::string(value).substr(inputboxValue[0].size() + 1);
size_t pos = newPath.find_last_not_of("/");
// Gotta have at least something but a /, and also needs to start with a /.
if (newPath.empty() || pos == newPath.npos || newPath[0] != '/') {
settingInfo_->Show(sy->T("ChangingMemstickPathInvalid", "That path couldn't be used to save Memory Stick files."), nullptr);
return;
}
if (pos != newPath.size() - 1) {
newPath = newPath.substr(0, pos + 1);
}
pendingMemstickFolder_ = newPath;
std::string promptMessage = sy->T("ChangingMemstickPath", "Save games, save states, and other data will not be copied to this folder.\n\nChange the Memory Stick folder?");
if (!File::Exists(newPath)) {
promptMessage = sy->T("ChangingMemstickPathNotExists", "That folder doesn't exist yet.\n\nSave games, save states, and other data will not be copied to this folder.\n\nCreate a new Memory Stick folder?");
}
// Add the path for clarity and proper confirmation.
promptMessage += "\n\n" + newPath + "/";
screenManager()->push(new PromptScreen(promptMessage, di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackMemstickFolder, this, std::placeholders::_1)));
}
#endif
}
}
#if PPSSPP_PLATFORM(ANDROID)
void GameSettingsScreen::CallbackMemstickFolder(bool yes) {
I18NCategory *sy = GetI18NCategory("System");
if (yes) {
std::string memstickDirFile = g_Config.internalDataDirectory + "/memstick_dir.txt";
std::string testWriteFile = pendingMemstickFolder_ + "/.write_verify_file";
// Already, create away.
if (!File::Exists(pendingMemstickFolder_)) {
File::CreateFullPath(pendingMemstickFolder_);
}
if (!writeDataToFile(true, "1", 1, testWriteFile.c_str())) {
settingInfo_->Show(sy->T("ChangingMemstickPathInvalid", "That path couldn't be used to save Memory Stick files."), nullptr);
return;
}
File::Delete(testWriteFile);
writeDataToFile(true, pendingMemstickFolder_.c_str(), pendingMemstickFolder_.size(), memstickDirFile.c_str());
// Save so the settings, at least, are transferred.
g_Config.memStickDirectory = pendingMemstickFolder_ + "/";
g_Config.Save();
screenManager()->RecreateAllViews();
}
}
#endif
void GameSettingsScreen::CallbackRenderingBackend(bool yes) {
// If the user ends up deciding not to restart, set the config back to the current backend
// so it doesn't get switched by accident.
+13 -3
View File
@@ -17,6 +17,7 @@
#pragma once
#include "ppsspp_config.h"
#include "ui/ui_screen.h"
#include "UI/MiscScreens.h"
@@ -30,6 +31,7 @@ public:
void update() override;
void onFinish(DialogResult result) override;
void sendMessage(const char *message, const char *value) override;
std::string tag() const override { return "settings"; }
UI::Event OnRecentChanged;
@@ -39,6 +41,9 @@ protected:
void CallbackRestoreDefaults(bool yes);
void CallbackRenderingBackend(bool yes);
void CallbackRenderingDevice(bool yes);
#if PPSSPP_PLATFORM(ANDROID)
void CallbackMemstickFolder(bool yes);
#endif
bool UseVerticalLayout() const;
private:
@@ -91,7 +96,9 @@ private:
UI::EventReturn OnRenderingBackend(UI::EventParams &e);
UI::EventReturn OnRenderingDevice(UI::EventParams &e);
UI::EventReturn OnJitAffectingSetting(UI::EventParams &e);
#ifdef _WIN32
#if PPSSPP_PLATFORM(ANDROID)
UI::EventReturn OnChangeMemStickDir(UI::EventParams &e);
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
UI::EventReturn OnSavePathMydoc(UI::EventParams &e);
UI::EventReturn OnSavePathOther(UI::EventParams &e);
#endif
@@ -107,8 +114,7 @@ private:
UI::EventReturn OnSavedataManager(UI::EventParams &e);
UI::EventReturn OnSysInfo(UI::EventParams &e);
// Temporaries to convert bools to int settings
bool cap60FPS_;
// Temporaries to convert setting types.
int iAlternateSpeedPercent1_;
int iAlternateSpeedPercent2_;
bool enableReports_;
@@ -122,6 +128,10 @@ private:
bool resolutionEnable_;
bool bloomHackEnable_;
bool tessHWEnable_;
#if PPSSPP_PLATFORM(ANDROID)
std::string pendingMemstickFolder_;
#endif
};
class SettingInfoMessage : public UI::LinearLayout {
+30 -45
View File
@@ -58,8 +58,8 @@
#include "Core/HLE/sceUmd.h"
#ifdef _WIN32
#include "Windows/W32Util/ShellUtil.h"
#include "Windows/MainWindow.h"
// Unfortunate, for undef DrawText...
#include "Common/CommonWindows.h"
#endif
#ifdef ANDROID_NDK_PROFILER
@@ -67,12 +67,6 @@
#include "android/android-ndk-profiler/prof.h"
#endif
#ifdef USING_QT_UI
#include <QFileDialog>
#include <QFile>
#include <QDir>
#endif
#include <sstream>
bool MainScreen::showHomebrewTab = false;
@@ -447,12 +441,18 @@ GameBrowser::GameBrowser(std::string path, bool allowBrowsing, bool *gridStyle,
Refresh();
}
void GameBrowser::FocusGame(std::string gamePath) {
void GameBrowser::FocusGame(const std::string &gamePath) {
focusGamePath_ = gamePath;
Refresh();
focusGamePath_.clear();
}
void GameBrowser::SetPath(const std::string &path) {
path_.SetPath(path);
g_Config.currentDirectory = path_.GetPath();
Refresh();
}
UI::EventReturn GameBrowser::LayoutChange(UI::EventParams &e) {
*gridStyle_ = e.a == 0 ? true : false;
Refresh();
@@ -466,30 +466,18 @@ UI::EventReturn GameBrowser::LastClick(UI::EventParams &e) {
UI::EventReturn GameBrowser::HomeClick(UI::EventParams &e) {
#ifdef __ANDROID__
path_.SetPath(g_Config.memStickDirectory);
#elif defined(USING_QT_UI)
I18NCategory *mm = GetI18NCategory("MainMenu");
QString fileName = QFileDialog::getExistingDirectory(NULL, "Browse for Folder", g_Config.currentDirectory.c_str());
if (QDir(fileName).exists())
path_.SetPath(fileName.toStdString());
else
return UI::EVENT_DONE;
#elif defined(_WIN32)
#if PPSSPP_PLATFORM(UWP)
SetPath(g_Config.memStickDirectory);
#elif defined(USING_QT_UI) || defined(USING_WIN_UI)
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
System_SendMessage("browse_folder", "");
}
#elif PPSSPP_PLATFORM(UWP)
// TODO UWP
SetPath(g_Config.memStickDirectory);
#else
I18NCategory *mm = GetI18NCategory("MainMenu");
std::string folder = W32Util::BrowseForFolder(MainWindow::GetHWND(), mm->T("Choose folder"));
if (!folder.size())
return UI::EVENT_DONE;
path_.SetPath(folder);
#endif
#else
path_.SetPath(getenv("HOME"));
SetPath(getenv("HOME"));
#endif
g_Config.currentDirectory = path_.GetPath();
Refresh();
return UI::EVENT_DONE;
}
@@ -533,7 +521,7 @@ void GameBrowser::Refresh() {
if (allowBrowsing_) {
topBar->Add(new Spacer(2.0f));
topBar->Add(new TextView(path_.GetFriendlyPath().c_str(), ALIGN_VCENTER | FLAG_WRAP_TEXT, true, new LinearLayoutParams(FILL_PARENT, 64.0f, 1.0f)));
#if defined(_WIN32) || defined(USING_QT_UI)
#if defined(USING_WIN_UI) || defined(USING_QT_UI)
topBar->Add(new Choice(mm->T("Browse", "Browse..."), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::HomeClick);
#else
topBar->Add(new Choice(mm->T("Home"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::HomeClick);
@@ -742,7 +730,7 @@ UI::EventReturn GameBrowser::GameButtonHighlight(UI::EventParams &e) {
}
UI::EventReturn GameBrowser::NavigateClick(UI::EventParams &e) {
DirButton *button = static_cast<DirButton *>(e.v);
DirButton *button = static_cast<DirButton *>(e.v);
std::string text = button->GetPath();
if (button->PathAbsolute()) {
path_.SetPath(text);
@@ -916,8 +904,7 @@ void MainScreen::CreateViews() {
TextView *ver = rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -6, 0, 0))));
ver->SetSmall(true);
ver->SetClip(false);
// Temporarily disabled the load button for Qt. See #11721
#if defined(_WIN32) // || defined(USING_QT_UI)
#if defined(USING_WIN_UI) || defined(USING_QT_UI)
rightColumnItems->Add(new Choice(mm->T("Load","Load...")))->OnClick.Handle(this, &MainScreen::OnLoadFile);
#endif
rightColumnItems->Add(new Choice(mm->T("Game Settings", "Settings")))->OnClick.Handle(this, &MainScreen::OnGameSettings);
@@ -1009,8 +996,16 @@ void MainScreen::sendMessage(const char *message, const char *value) {
// Always call the base class method first to handle the most common messages.
UIScreenWithBackground::sendMessage(message, value);
if (!strcmp(message, "boot") && screenManager()->topScreen() == this) {
screenManager()->switchScreen(new EmuScreen(value));
if (screenManager()->topScreen() == this) {
if (!strcmp(message, "boot")) {
screenManager()->switchScreen(new EmuScreen(value));
}
if (!strcmp(message, "browse_folderSelect")) {
int tab = tabHolder_->GetCurrentTab();
if (tab >= 0 && tab < (int)gameBrowsers_.size()) {
gameBrowsers_[tab]->SetPath(value);
}
}
}
if (!strcmp(message, "permission_granted") && !strcmp(value, "storage")) {
RecreateViews();
@@ -1032,16 +1027,6 @@ bool MainScreen::UseVerticalLayout() const {
}
UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) {
#if defined(USING_QT_UI)
QString fileName = QFileDialog::getOpenFileName(NULL, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf *.zip *.ppdmp)");
if (QFile::exists(fileName)) {
QDir newPath;
g_Config.currentDirectory = newPath.filePath(fileName).toStdString();
g_Config.Save();
screenManager()->switchScreen(new EmuScreen(fileName.toStdString()));
}
#endif
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
System_SendMessage("browse_file", "");
}
+2 -1
View File
@@ -34,7 +34,8 @@ public:
UI::Choice *HomebrewStoreButton() { return homebrewStoreButton_; }
void FocusGame(std::string gamePath);
void FocusGame(const std::string &gamePath);
void SetPath(const std::string &path);
protected:
virtual bool DisplayTopBar();
+9
View File
@@ -466,6 +466,15 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
// most sense.
g_Config.memStickDirectory = std::string(external_dir) + "/";
g_Config.flash0Directory = std::string(external_dir) + "/flash0/";
std::string memstickDirFile = g_Config.internalDataDirectory + "/memstick_dir.txt";
if (File::Exists(memstickDirFile)) {
std::string memstickDir;
readFileToString(true, memstickDirFile.c_str(), memstickDir);
if (!memstickDir.empty() && File::Exists(memstickDir)) {
g_Config.memStickDirectory = memstickDir + "/";
}
}
#elif defined(IOS)
g_Config.memStickDirectory = user_data_path;
g_Config.flash0Directory = std::string(external_dir) + "/flash0/";
+9 -4
View File
@@ -50,6 +50,7 @@ namespace MainWindow {
static std::unordered_map<int, std::string> initialMenuKeys;
static std::vector<std::string> availableShaders;
static std::string menuLanguageID = "";
static int menuKeymapGeneration = -1;
static bool menuShaderInfoLoaded = false;
std::vector<ShaderInfo> menuShaderInfo;
@@ -224,6 +225,10 @@ namespace MainWindow {
}
void DoTranslateMenus(HWND hWnd, HMENU menu) {
auto useDefHotkey = [](int virtkey) {
return KeyMap::g_controllerMap[virtkey].empty();
};
TranslateMenuItem(menu, ID_FILE_MENU);
TranslateMenuItem(menu, ID_EMULATION_MENU);
TranslateMenuItem(menu, ID_DEBUG_MENU);
@@ -236,9 +241,9 @@ namespace MainWindow {
TranslateMenuItem(menu, ID_FILE_LOAD_DIR);
TranslateMenuItem(menu, ID_FILE_LOAD_MEMSTICK);
TranslateMenuItem(menu, ID_FILE_MEMSTICK);
TranslateMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, L"\tF3");
TranslateMenuItem(menu, ID_FILE_QUICKLOADSTATE, L"\tF4");
TranslateMenuItem(menu, ID_FILE_QUICKSAVESTATE, L"\tF2");
TranslateMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, useDefHotkey(VIRTKEY_NEXT_SLOT) ? L"\tF3" : L"");
TranslateMenuItem(menu, ID_FILE_QUICKLOADSTATE, useDefHotkey(VIRTKEY_LOAD_STATE) ? L"\tF4" : L"");
TranslateMenuItem(menu, ID_FILE_QUICKSAVESTATE, useDefHotkey(VIRTKEY_SAVE_STATE) ? L"\tF2" : L"");
TranslateMenuItem(menu, ID_FILE_LOADSTATEFILE);
TranslateMenuItem(menu, ID_FILE_SAVESTATEFILE);
TranslateMenuItem(menu, ID_FILE_RECORD_MENU);
@@ -349,7 +354,7 @@ namespace MainWindow {
bool changed = false;
const std::string curLanguageID = i18nrepo.LanguageID();
if (curLanguageID != menuLanguageID) {
if (curLanguageID != menuLanguageID || menuKeymapGeneration != KeyMap::g_controllerMapGeneration) {
DoTranslateMenus(hWnd, menu);
menuLanguageID = curLanguageID;
changed = true;
+75 -11
View File
@@ -21,15 +21,17 @@
#include "Common/CommonWindows.h"
#include "Common/OSVersion.h"
#include "Common/Vulkan/VulkanLoader.h"
#include <Wbemidl.h>
#include <shellapi.h>
#include <mmsystem.h>
#include "base/NativeApp.h"
#include "base/display.h"
#include "file/vfs.h"
#include "file/zip_read.h"
#include "base/NativeApp.h"
#include "i18n/i18n.h"
#include "profiler/profiler.h"
#include "thread/threadutil.h"
#include "util/text/utf8.h"
@@ -57,6 +59,7 @@
#include "Windows/GEDebugger/GEDebugger.h"
#include "Windows/W32Util/DialogManager.h"
#include "Windows/W32Util/ShellUtil.h"
#include "Windows/Debugger/CtrlDisAsmView.h"
#include "Windows/Debugger/CtrlMemView.h"
@@ -273,6 +276,11 @@ void System_SendMessage(const char *command, const char *parameter) {
}
} else if (!strcmp(command, "browse_file")) {
MainWindow::BrowseAndBoot("");
} else if (!strcmp(command, "browse_folder")) {
I18NCategory *mm = GetI18NCategory("MainMenu");
std::string folder = W32Util::BrowseForFolder(MainWindow::GetHWND(), mm->T("Choose folder"));
if (folder.size())
NativeMessageReceived("browse_folderSelect", folder.c_str());
} else if (!strcmp(command, "bgImage_browse")) {
MainWindow::BrowseBackground();
} else if (!strcmp(command, "toggle_fullscreen")) {
@@ -350,6 +358,39 @@ static std::string GetDefaultLangRegion() {
}
}
static const int EXIT_CODE_VULKAN_WORKS = 42;
static bool DetectVulkanInExternalProcess() {
wchar_t moduleFilename[MAX_PATH];
wchar_t workingDirectory[MAX_PATH];
GetCurrentDirectoryW(MAX_PATH, workingDirectory);
const wchar_t *cmdline = L"--vulkan-available-check";
GetModuleFileName(GetModuleHandle(NULL), moduleFilename, MAX_PATH);
SHELLEXECUTEINFO info{ sizeof(SHELLEXECUTEINFO) };
info.fMask = SEE_MASK_NOCLOSEPROCESS;
info.lpFile = moduleFilename;
info.lpParameters = cmdline;
info.lpDirectory = workingDirectory;
info.nShow = SW_HIDE;
if (ShellExecuteEx(&info) != TRUE) {
return false;
}
if (info.hProcess == nullptr) {
return false;
}
DWORD result = WaitForSingleObject(info.hProcess, 10000);
DWORD exitCode = 0;
if (result == WAIT_FAILED || GetExitCodeProcess(info.hProcess, &exitCode) == 0) {
CloseHandle(info.hProcess);
return false;
}
CloseHandle(info.hProcess);
return exitCode == EXIT_CODE_VULKAN_WORKS;
}
std::vector<std::wstring> GetWideCmdLine() {
wchar_t **wargv;
int wargc = -1;
@@ -361,9 +402,7 @@ std::vector<std::wstring> GetWideCmdLine() {
return wideArgs;
}
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
setCurrentThreadName("Main");
static void WinMainInit() {
CoInitializeEx(NULL, COINIT_MULTITHREADED);
net::Init(); // This needs to happen before we load the config. So on Windows we also run it in Main. It's fine to call multiple times.
@@ -384,6 +423,21 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
// FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it.
_set_FMA3_enable(0);
#endif
}
static void WinMainCleanup() {
if (g_Config.bRestartRequired) {
W32Util::ExitAndRestart();
}
net::Shutdown();
CoUninitialize();
}
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
setCurrentThreadName("Main");
WinMainInit();
#ifndef _DEBUG
bool showLog = false;
@@ -486,12 +540,28 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
g_Config.bSoftwareRendering = true;
}
}
// This should only be called by DetectVulkanInExternalProcess().
if (wideArgs[i] == L"--vulkan-available-check") {
// Just call it, this way it will crash here if it doesn't work.
// (this is an external process.)
bool result = VulkanMayBeAvailable();
LogManager::Shutdown();
WinMainCleanup();
return result ? EXIT_CODE_VULKAN_WORKS : EXIT_FAILURE;
}
}
}
#ifdef _DEBUG
g_Config.bEnableLogging = true;
#endif
#ifndef _DEBUG
// See #11719 - too many Vulkan drivers crash on basic init.
VulkanSetAvailable(DetectVulkanInExternalProcess());
#endif
if (iCmdShow == SW_MAXIMIZE) {
// Consider this to mean --fullscreen.
g_Config.bFullScreen = true;
@@ -595,13 +665,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
timeEndPeriod(1);
LogManager::Shutdown();
if (g_Config.bRestartRequired) {
W32Util::ExitAndRestart();
}
net::Shutdown();
CoUninitialize();
WinMainCleanup();
return 0;
}
+145 -21
View File
@@ -31,15 +31,31 @@
[VertexDepthRounding]
# Phantasy Star Portable needs depth rounding to 16-bit precision for text to show up.
# It's enough to do it at the vertex granularity. #3777
# Phantasy Star Portable
ULJM05309 = true
ULUS10410 = true
ULES01218 = true
ULJM08023 = true
ULES01218 = true
# Phantasy Star Portable 2 JP (missing text)
# Phantasy Star Portable 1 Demo
NPUH90023 = true
# Phantasy Star Portable 2
ULES01439 = true
ULUS10529 = true
ULJM05493 = true
NPJH50043 = true
ULJM08030 = true
NPUH90023 = true
ULJM91014 = true
NPJH90002 = true
ULJM05732 = true
NPJH50332 = true
# Phantasy Star Portable 2 JP Demo
ULJM91018 = true
NPJH90062 = true
# Phantasy Star Portable Infinity Demo
NPJH90157 = true # Infinity demo
# Puyo Puyo Fever 2 #3663 (layering)
ULJM05058 = true
# NBA 2K13 #6603 (menu glitches)
@@ -72,23 +88,30 @@ ULJS00454 = true
# Heroes Phantasia Limited Edition Disc requires pixel depth rounding.
ULJS00455 = true
# Phantasy Star games flickering
# Phantasy Star Portable 1
# Phantasy Star Portable
ULJM05309 = true
ULUS10410 = true
ULES01218 = true
ULJM08023 = true
ULES01218 = true
# Phantasy Star Portable 2 JP
# Phantasy Star Portable 1 Demo
NPUH90023 = true
# Phantasy Star Portable 2
ULES01439 = true
ULUS10529 = true
ULJM05493 = true
NPJH50043 = true
ULJM08030 = true
# Phantasy Star Portable 1 Demo
NPUH90023 = true
ULJM91014 = true
NPJH90002 = true
ULJM05732 = true
NPJH50332 = true
# Phantasy Star Portable 2 JP Demo
ULJM91018 = true
NPJH90062 = true
# Phantasy Star Portable Infinity Demo
NPJH90157 = true # Infinity demo
# Nayuta no Kiseki see #8744 - flickering textures at some locations
NPJH50625 = true
@@ -96,25 +119,54 @@ NPJH50625 = true
# Phantasy Star Portable 2 and Infinity both use viewport depth outside [0, 1].
# This gets clamped in our current implementation, but attempts to fix it run into
# Other bugs, so we've restored this hack for now.
# Phantasy Star Portable
ULJM05309 = true
ULUS10410 = true
ULES01218 = true
ULJM08023 = true
ULES01218 = true
# Phantasy Star Portable 1 Demo
NPUH90023 = true
# Phantasy Star Portable 2
ULES01439 = true
ULUS10529 = true
ULJM05493 = true
NPJH50043 = true
ULJM08030 = true
ULES01439 = true
ULUS10529 = true
ULJM91018 = true # Infinity demo disc?
NPJH90157 = true # Infinity demo
NPUH90023 = true
ULJM91014 = true
NPJH90002 = true
ULJM05732 = true
NPJH50332 = true
# Phantasy Star Portable 2 JP Demo
ULJM91018 = true
NPJH90062 = true
# Phantasy Star Portable Infinity Demo
NPJH90157 = true # Infinity demo
[ClearToRAM]
# SOCOM Navy Seals games require this. See issue #8973.
# Navy Seals
UCUS98615 = true
ULES00038 = true
UCKS45021 = true
# Fireteam Bravo 3
UCJS10102 = true
# Navy Seals : Tactical Strike
UCES00855 = true
UCUS98649 = true
NPJG00035 = true
NPJG90068 = true
UCJS10102 = true
# Tactical Strike demo
NPUG70003 = true
# Fireteam Bravo
UCKS45021 = true
UCUS98615 = true
UCES00038 = true
ULES00038 = true
# Fireteam Bravo 2
UCES00543 = true
UCUS98645 = true
# Fireteam Bravo 2 Demo
UCUS98677 = true
UCUS98691 = true
# Fireteam Bravo 3
NPHG00032 = true
UCUS98716 = true
UCES01242 = true
@@ -146,10 +198,13 @@ UCES00373 = true
# It makes sceGeDrawSync eat a lot of cycles which can affect timing in lots of games,
# might be negative for others, but happens to fix games below.
# Crash Tag Team Racing needs it to pass checking memory stick screen.
ULUS10044 = true
ULES00168 = true
ULES00169 = true
ULES00170 = true
ULES00171 = true
ULES00172 = true
ULJM05036 = true
ULUS10044 = true
# Gundam Battle Royale might need it to avoid crashes when certain Ace enemies shows up
ULJS00083 = true
ULKS46104 = true
@@ -171,6 +226,7 @@ UCKS45033 = true
UCJS18014 = true
UCUS98700 = true
NPJG00032 = true
UCJX90019 = true
# Fixes Patapon 2 title screen double framerate
UCJS10089 = true
NPJG00010 = true
@@ -296,17 +352,41 @@ ULJM05255 = true
ULJM05359 = true
ULJM05885 = true
NPJH50825 = true
# GOW : JP/Korean
UCJS10114 = true
UCKS45084 = true
# GOW : Ghost of Sparta
UCUS98737 = true
UCAS40323 = true
NPHG00092 = true
NPEG00044 = true
NPEG00045 = true
NPJG00120 = true
NPUG80508 = true
UCJS10114 = true
UCES01401 = true
UCES01473 = true
# GOW : Ghost of Sparta Demo
NPJG90095 = true
NPEG90035 = true
NPUG70125 = true
# GOW : Chains Of Olympus
UCAS40198 = true
UCUS98653 = true
UCUS98705 = true
UCES00842 = true
ULJM05438 = true
ULJM05348 = true
UCKS45084 = true
NPUG80325 = true
NPEG00023 = true
NPHG00027 = true
NPHG00028 = true
NPJG00120 = true
NPJH50170 = true
UCET00844 = true
# GOW: Chains of Olympus Demo
UCUS98705 = true
UCED00971 = true
UCUS98713 = true
# Daxter
UCUS98618 = true
UCES00044 = true
@@ -355,6 +435,7 @@ ULES00740 = true
# Chili Con Carnage
ULUS10216 = true
ULES00629 = true
# TODO: There are many more.
[RequireBlockTransfer]
# Warn the user that the game will have issue graphic, if simulate block transfer is not enabled.
@@ -372,6 +453,8 @@ ULES01556 = true
ULJM05170 = true
ULJM08033 = true
NPJH50373 = true
NPUH10191 = true
NPUH10197 = true
# Grand Knights History need it to fix blackboxes on characters and flickering texture . See issues #2135 , #6099
ULJS00394 = true
ULJS19068 = true
@@ -401,6 +484,9 @@ ULUS10025 = true
ULJM05228 = true
NPJH50305 = true
ULJM05049 = true
ULKS46027 = true
ULAS42019 = true
# Dominator
ULUS10236 = true
ULES00750 = true
@@ -408,6 +494,7 @@ ULJM05242 = true
ULJM05371 = true
NPJH50304 = true
ULES00703 = true
ULAS42095 = true
[RequireDefaultCPUClock]
# GOW : Ghost of Sparta
@@ -415,12 +502,22 @@ UCUS98737 = true
UCAS40323 = true
NPHG00092 = true
NPEG00044 = true
NPEG00045 = true
NPJG00120 = true
NPUG80508 = true
UCJS10114 = true
UCES01401 = true
UCES01473 = true
# GOW : Ghost of Sparta Demo
NPJG90095 = true
NPEG90035 = true
NPUG70125 = true
[MGS2AcidHack]
ULES00008 = true
ULES00284 = true
ULJM05047 = true
ULKS46065 = true
ULJM08001 = true
ULJM05001 = true
ULAS42007 = true
@@ -432,6 +529,7 @@ ULES00622 = true # SR1
ULUS10195 = true # SR1
ULUS10323 = true # SR2
ULES00940 = true # SR2
ULET00958 = true
[AdhocHackDisableNBSwitch]
ULJS00250 = true
@@ -444,6 +542,12 @@ NPJH50686 = true # Digimon Adventures (JP, and English patches...)
ULJS00078 = true # MotoGP
ULUS10153 = true # MotoGP
UCES00373 = true # MotoGP
ULUS10551 = true # Ys Seven
ULJM05475 = true # Ys Seven JP
ULUS10549 = true # Ys Seven
NPEH00065 = true # Ys Seven
NPJH50350 = true # Ys Seven
ULJM08041 = true # Ys Seven
[YugiohSaveFix]
# The cause of Yu-gi-oh series 's bad save (cannot save) are load "save status" and use cwcheat,
@@ -472,10 +576,11 @@ ULES01362 = true
# Yu-Gi-Oh! 5D's Tag Force 5
ULUS10555 = true
ULJM05734 = true
ULES01474 = true
# Yu-Gi-Oh! 5D's Tag Force 6
ULJM-05940 = true
NPJH-50794 = true
ULJM05940 = true
NPJH50794 = true
# Yu-Gi-Oh! 5D's Tag Force
ULJM05940 = true
@@ -487,31 +592,50 @@ NPJH00142 = true
# F1 2006 won't boot at all with our standard unrealistically fast timing.
UCES00238 = true
UCJS10045 = true
# F1 2005, japan only?
UCJS10019 = true
[ForceMax60FPS]
# The GOW games are very heavy and render as fast as they can. They benefit greatly from
# capping the framerate at 60fps.
UCJS10114 = true
UCKS45084 = true
# GOW : Ghost of Sparta
UCUS98737 = true
UCAS40323 = true
NPHG00092 = true
NPEG00044 = true
NPEG00045 = true
NPJG00120 = true
NPUG80508 = true
UCJS10114 = true
UCES01401 = true
UCES01473 = true
# GOW : Ghost of Sparta Demo
NPEG90035 = true
NPUG70125 = true
NPJG90095 = true
# GOW : Chains Of Olympus
UCAS40198 = true
UCUS98653 = true
UCUS98705 = true
UCES00842 = true
ULJM05438 = true
ULJM05348 = true
UCKS45084 = true
NPUG80325 = true
NPEG00023 = true
NPHG00027 = true
NPHG00028 = true
NPJG00120 = true
NPJH50170 = true
UCET00844 = true
# GOW: Chains of Olympus Demo
UCUS98705 = true
UCED00971 = true
UCUS98713 = true
# F1 2006 has extremely long loading times if we don't limit the framerate.
UCES00238 = true
UCJS10045 = true
# F1 2005, japan only?
UCJS10019 = true
+3 -3
View File
@@ -81,8 +81,6 @@ void TextDrawerQt::DrawString(DrawBuffer &target, const char *str, float x, floa
auto iter = cache_.find(entryHash);
if (iter != cache_.end()) {
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
draw_->BindTexture(0, entry->texture);
} else {
QFont *font = fontMap_.find(fontHash_)->second;
QFontMetrics fm(*font);
@@ -104,7 +102,6 @@ void TextDrawerQt::DrawString(DrawBuffer &target, const char *str, float x, floa
entry = new TextStringEntry();
entry->bmWidth = entry->width = image.width();
entry->bmHeight = entry->height = image.height();
entry->lastUsedFrame = frameCount_;
TextureDesc desc{};
desc.type = TextureType::LINEAR2D;
@@ -126,8 +123,11 @@ void TextDrawerQt::DrawString(DrawBuffer &target, const char *str, float x, floa
delete[] bitmapData;
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);
}
float w = entry->bmWidth * fontScaleX_;
float h = entry->bmHeight * fontScaleY_;
entry->lastUsedFrame = frameCount_;
draw_->BindTexture(0, entry->texture);
DrawBuffer::DoAlign(align, &x, &y, &w, &h);
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
target.Flush(true);