mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
# Conflicts: # UI/GameSettingsScreen.cpp # assets/compat.ini
This commit is contained in:
commit
1bf74bd58c
25 files changed
+749
-330
No files matched your search
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ class IniFile;
|
||||
|
||||
namespace KeyMap {
|
||||
extern KeyMapping g_controllerMap;
|
||||
extern int g_controllerMapGeneration;
|
||||
|
||||
// Key & Button names
|
||||
struct KeyMap_IntStrPair {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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 ¶ms) {
|
||||
UI::EventReturn ControlMapper::OnDelete(UI::EventParams ¶ms) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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/";
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
|
||||
+1
-1
Submodule pspautotests updated: 98b83d2cb0...32d3e0426a.
Reference in new issue
Block a user