diff --git a/Common/GPU/Shader.cpp b/Common/GPU/Shader.cpp index 2fe810bb7333..19becbd320b7 100644 --- a/Common/GPU/Shader.cpp +++ b/Common/GPU/Shader.cpp @@ -50,6 +50,7 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) { lastFragData = nullptr; gles = false; forceMatrix4x4 = true; + depthMinusOneToOne = true; break; case GLSL_3xx: // Just used in the shader test. @@ -67,6 +68,7 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) { gles = true; forceMatrix4x4 = true; glslES30 = true; + depthMinusOneToOne = true; break; case GLSL_VULKAN: fragColor0 = "fragColor0"; @@ -86,6 +88,7 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) { forceMatrix4x4 = false; coefsFromBuffers = true; vertexIndex = true; + depthMinusOneToOne = false; break; case HLSL_D3D11: fragColor0 = "outfragment.target"; @@ -107,6 +110,7 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) { coefsFromBuffers = true; vsOutPrefix = "Out."; viewportYSign = "-"; + depthMinusOneToOne = false; break; } } diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 5dbb6a549090..45e54cab5464 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -57,6 +57,7 @@ struct ShaderLanguageDesc { const char *vsOutPrefix = ""; const char *viewportYSign = ""; + bool depthMinusOneToOne = false; bool vertexIndex = false; bool glslES30 = false; // really glslES30Features. TODO: Clean this up. bool bitwiseOps = false; diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index ecdee31eb107..1bcfa95b6835 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -361,6 +361,9 @@ void ShaderWriter::EndVSMain(Slice varyings) { if (strlen(lang_.viewportYSign)) { F(" gl_Position.y *= %s1.0;\n", lang_.viewportYSign); } + if (lang_.depthMinusOneToOne) { + F(" gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n"); // homogenous math... looks confusing. + } C(" vs_out.pos = gl_Position;\n"); for (auto &varying : varyings) { F(" vs_out.%s = %s;\n", varying.name, varying.name); diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index 617d231de51b..6df3e6786482 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -441,6 +441,10 @@ class VulkanContext { return winsys_; } + bool SupportsPreRotation() const { + return surfCapabilities_.supportedTransforms != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + } + private: bool ChooseQueue(); diff --git a/Common/Log.h b/Common/Log.h index 1e672cec6020..268bfc35fb39 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -57,6 +57,7 @@ enum class Log { GeDebugger, UI, IAP, + CwCheats, sceAudio, sceCtrl, diff --git a/Common/Log/LogManager.cpp b/Common/Log/LogManager.cpp index 3c1a4b3bb6b0..dff5ecba86f6 100644 --- a/Common/Log/LogManager.cpp +++ b/Common/Log/LogManager.cpp @@ -96,6 +96,7 @@ static const char * const g_logTypeNames[] = { "GEDEBUGGER", "UI", "IAP", + "CWCHEATS", "SCEAUDIO", "SCECTRL", "SCEDISP", diff --git a/Common/Math/lin/matrix4x4.cpp b/Common/Math/lin/matrix4x4.cpp index e341210cee74..44a689ff7c3e 100644 --- a/Common/Math/lin/matrix4x4.cpp +++ b/Common/Math/lin/matrix4x4.cpp @@ -43,7 +43,7 @@ void Matrix4x4::setViewFrame(const Vec3 &pos, const Vec3 &vRight, const Vec3 &vV ww = 1.0f; } -void Matrix4x4::setOrtho(float left, float right, float bottom, float top, float near, float far) { +void Matrix4x4::setOrthoGL(float left, float right, float bottom, float top, float near, float far) { empty(); xx = 2.0f / (right - left); yy = 2.0f / (top - bottom); diff --git a/Common/Math/lin/matrix4x4.h b/Common/Math/lin/matrix4x4.h index 575b6a61d431..eec421258336 100644 --- a/Common/Math/lin/matrix4x4.h +++ b/Common/Math/lin/matrix4x4.h @@ -87,7 +87,7 @@ class Matrix4x4 { ww = 1.0f; } - void setOrtho(float left, float right, float bottom, float top, float near, float far); + void setOrthoGL(float left, float right, float bottom, float top, float near, float far); void setOrthoD3D(float left, float right, float bottom, float top, float near, float far); void setOrthoVulkan(float left, float right, float top, float bottom, float near, float far); diff --git a/Common/System/Display.cpp b/Common/System/Display.cpp index aae1776a57c7..0356a1cba116 100644 --- a/Common/System/Display.cpp +++ b/Common/System/Display.cpp @@ -138,7 +138,7 @@ Lin::Matrix4x4 ComputeOrthoMatrix(float xres, float yres, CoordConvention coordC break; case CoordConvention::OpenGL: default: - ortho.setOrtho(0.0f, xres, yres, 0.0f, -1.0f, 1.0f); + ortho.setOrthoGL(0.0f, xres, yres, 0.0f, -1.0f, 1.0f); break; } // Compensate for rotated display if needed. diff --git a/Common/UI/Notice.h b/Common/UI/Notice.h index e35710ae76d2..5962e7750200 100644 --- a/Common/UI/Notice.h +++ b/Common/UI/Notice.h @@ -34,9 +34,6 @@ class NoticeView : public UI::InertView { level_ = level; text_ = text; } - void SetSquishy(bool squishy) { - squishy_ = squishy; - } void SetWrapText(bool wrapText) { wrapText_ = wrapText; } @@ -53,8 +50,7 @@ class NoticeView : public UI::InertView { std::string iconName_; NoticeLevel level_; mutable float height1_ = 0.0f; - bool squishy_ = false; - bool wrapText_ = false; + bool wrapText_ = true; }; ImageID GetOSDIcon(NoticeLevel level); diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 325677df6bc4..b78dc024df6a 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -816,6 +816,7 @@ void AskForInput(ScreenManager *screenManager, RequesterToken token, UI::View *s PopupTextInputChoice::PopupTextInputChoice(RequesterToken token, std::string *value, std::string_view title, std::string_view placeholder, int maxLen, ScreenManager *screenManager, LayoutParams *layoutParams) : AbstractChoiceWithValueDisplay(title, layoutParams), screenManager_(screenManager), value_(value), placeHolder_(placeholder), maxLen_(maxLen), token_(token), restriction_(StringRestriction::None) { + _dbg_assert_(value); OnClick.Handle(this, &PopupTextInputChoice::HandleClick); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 18bc85c09215..dc4c41fc9468 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -3185,9 +3185,9 @@ bool GetOutputFramebuffer(Draw::DrawContext *draw, GPUDebugBuffer &buffer) { if (fmt != Draw::DataFormat::B8G8R8A8_UNORM) fmt = Draw::DataFormat::R8G8B8A8_UNORM; - bool flipped = g_Config.iGPUBackend == (int)GPUBackend::OPENGL; + bool flipY = g_Config.iGPUBackend == (int)GPUBackend::OPENGL; - buffer.Allocate(w, h, fmt == Draw::DataFormat::R8G8B8A8_UNORM ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA, flipped); + buffer.Allocate(w, h, fmt == Draw::DataFormat::R8G8B8A8_UNORM ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA, flipY); buffer.SetIsBackbuffer(true); return draw->CopyFramebufferToMemory(nullptr, Draw::Aspect::COLOR_BIT, 0, 0, w, h, fmt, buffer.GetData(), w, Draw::ReadbackMode::BLOCK, "GetOutputFramebuffer"); } diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 35985587caa3..75e9fd134445 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -14,18 +14,12 @@ using namespace Lin; -static void ConvertProjMatrixToVulkan(Matrix4x4 &in) { +static void ConvertProjMatrixToZeroToOneDepth(Matrix4x4 &in) { const Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); in.translateAndScale(trans, scale); } -static void ConvertProjMatrixToD3D11(Matrix4x4 &in) { - const Vec3 trans(gstate_c.vpXOffset, -gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); - const Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); - in.translateAndScale(trans, scale); -} - void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ) { // Account for the projection viewport adjustment when viewport is too large. auto reverseViewportX = [](float x) { @@ -72,6 +66,40 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo maxValues[3] = NAN; } +// TODO: This will be removed later. +static inline void FlipProjMatrix(Matrix4x4 & in) { + const bool invertedY = gstate_c.vpHeight < 0; + if (invertedY) { + in[1] = -in[1]; + in[5] = -in[5]; + in[9] = -in[9]; + in[13] = -in[13]; + } + const bool invertedX = gstate_c.vpWidth < 0; + if (invertedX) { + in[0] = -in[0]; + in[4] = -in[4]; + in[8] = -in[8]; + in[12] = -in[12]; + } +} + +void UpdateRotation(float rotMatrix[4], bool useBufferedRendering) { + if (!gstate_c.Use(GPU_USE_PRE_ROTATION) || useBufferedRendering) { + rotMatrix[0] = 1.0f; + rotMatrix[1] = 0.0f; + rotMatrix[2] = 0.0f; + rotMatrix[3] = 1.0f; + } else { + const DisplayRotation rotation = g_display.rotation; + // The others are ROTATE_90 and so on. + rotMatrix[0] = rotation == DisplayRotation::ROTATE_0 ? 1.0 : (rotation == DisplayRotation::ROTATE_180 ? -1.0 : 0.0); + rotMatrix[1] = rotation == DisplayRotation::ROTATE_90 ? 1.0 : (rotation == DisplayRotation::ROTATE_270 ? -1.0 : 0.0); + rotMatrix[2] = rotation == DisplayRotation::ROTATE_270 ? 1.0 : (rotation == DisplayRotation::ROTATE_90 ? -1.0 : 0.0); + rotMatrix[3] = rotation == DisplayRotation::ROTATE_0 ? 1.0 : (rotation == DisplayRotation::ROTATE_180 ? -1.0 : 0.0); + } +} + void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport, bool useBufferedRendering) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat3(ub->texEnvColor, gstate.texenvcolor); @@ -115,29 +143,8 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView Matrix4x4 flippedMatrix; memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); - const bool invertedY = gstate_c.vpHeight < 0; - if (invertedY) { - flippedMatrix[1] = -flippedMatrix[1]; - flippedMatrix[5] = -flippedMatrix[5]; - flippedMatrix[9] = -flippedMatrix[9]; - flippedMatrix[13] = -flippedMatrix[13]; - } - const bool invertedX = gstate_c.vpWidth < 0; - if (invertedX) { - flippedMatrix[0] = -flippedMatrix[0]; - flippedMatrix[4] = -flippedMatrix[4]; - flippedMatrix[8] = -flippedMatrix[8]; - flippedMatrix[12] = -flippedMatrix[12]; - } - if (flipViewport) { - ConvertProjMatrixToD3D11(flippedMatrix); - } else { - ConvertProjMatrixToVulkan(flippedMatrix); - } - - if (!useBufferedRendering && g_display.rotation != DisplayRotation::ROTATE_0) { - flippedMatrix = flippedMatrix * g_display.rot_matrix; - } + FlipProjMatrix(flippedMatrix); + ConvertProjMatrixToZeroToOneDepth(flippedMatrix); CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr()); ub->rotation = useBufferedRendering ? 0 : (float)g_display.rotation; @@ -145,14 +152,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { Matrix4x4 proj_through; - if (flipViewport) { - proj_through.setOrthoD3D(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1); - } else { - proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); - } - if (!useBufferedRendering && g_display.rotation != DisplayRotation::ROTATE_0) { - proj_through = proj_through * g_display.rot_matrix; - } + proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); // Negative RT offsets come from split framebuffers (Killzone) if (gstate_c.curRTOffsetX < 0 || gstate_c.curRTOffsetY < 0) { @@ -161,6 +161,8 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView } CopyMatrix4x4(ub->proj_through, proj_through.getReadPtr()); + + ub->rotation = useBufferedRendering ? 0 : (float)g_display.rotation; } // Transform diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 77c8ebc8de40..a63b12e2e09d 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -17,7 +17,7 @@ enum : uint64_t { DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT, }; -// Currently 496 bytes. +// Currently 480 bytes. // Every line here is a 4-float. struct alignas(16) UB_VS_FS_Base { float proj[16]; @@ -43,6 +43,7 @@ struct alignas(16) UB_VS_FS_Base { // VR stuff is to go here, later. For normal drawing, we can then get away // with just uploading the first 448 bytes of the struct (up to and including fogCoef). }; +static_assert(sizeof(UB_VS_FS_Base) == 480, "UB_VS_FS_Base should be 480 bytes"); static const char * const ub_baseStr = R"( mat4 u_proj; @@ -84,6 +85,7 @@ struct alignas(16) UB_VS_Lights { float lightDiffuse[4][4]; float lightSpecular[4][4]; }; +static_assert(sizeof(UB_VS_Lights) == 512); // it's ok to optimize this, it's just an assumption check. static const char * const ub_vs_lightsStr = R"( vec4 u_ambient; @@ -105,6 +107,7 @@ R"( vec4 u_ambient; struct alignas(16) UB_VS_Bones { float bones[8][12]; }; +static_assert(sizeof(UB_VS_Bones) == 384); // No way to optimize this further. static const char * const ub_vs_bonesStr = R"( mat3x4 u_bone0; mat3x4 u_bone1; mat3x4 u_bone2; mat3x4 u_bone3; mat3x4 u_bone4; mat3x4 u_bone5; mat3x4 u_bone6; mat3x4 u_bone7; mat3x4 u_bone8; diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 6ef76f3fbfa5..5c29975a3df5 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -65,27 +65,15 @@ static void SwapUVs(TransformedVertex &a, TransformedVertex &b) { // Note: 0 is BR and 2 is TL. -static void RotateUV(TransformedVertex v[4], bool flippedY) { - // We use the transformed tl/br coordinates to figure out whether they're flipped or not. - float ySign = flippedY ? -1.0 : 1.0; - +static void RotateUV(TransformedVertex v[4]) { const float x1 = v[2].x; const float x2 = v[0].x; - const float y1 = v[2].y * ySign; - const float y2 = v[0].y * ySign; - - if ((x1 < x2 && y1 < y2) || (x1 > x2 && y1 > y2)) - SwapUVs(v[1], v[3]); -} + const float y1 = v[2].y; + const float y2 = v[0].y; -static void RotateUVThrough(TransformedVertex v[4]) { - float x1 = v[2].x; - float x2 = v[0].x; - float y1 = v[2].y; - float y2 = v[0].y; - - if ((x1 < x2 && y1 > y2) || (x1 > x2 && y1 < y2)) + if ((x1 < x2 && y1 > y2) || (x1 > x2 && y1 < y2)) { SwapUVs(v[1], v[3]); + } } // Clears on the PSP are best done by drawing a series of vertical strips @@ -658,11 +646,7 @@ bool SoftwareTransform::ExpandRectangles(int vertexCount, int &numDecodedVerts, trans[3].v = transVtxBR.v * vscale; // That's the four corners. Now process UV rotation. - if (throughmode) { - RotateUVThrough(trans); - } else { - RotateUV(trans, params_.flippedY); - } + RotateUV(trans); // Triangle: BR-TR-TL indsOut[0] = i * 2 + 0; diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index ced337597085..52295fb9c2fd 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -363,6 +363,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } WRITE(p, "};\n"); } else { + // Non-Vulkan GLSL. if (enableBones) { const char * const * boneWeightDecl = boneWeightAttrDecl; if (!strcmp(compat.attribute, "in")) { @@ -479,8 +480,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "uniform lowp vec3 u_matemissive;\n"); *uniformMask |= DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE; } - } else { - WRITE(p, "uniform lowp float u_rotation;\n"); } if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { @@ -749,24 +748,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // The proj_through matrix already has the rotation, if needed. WRITE(p, " vec4 outPos = mul(u_proj_through, vec4(position.xyz, 1.0));\n"); } else { - if (compat.shaderLanguage == GLSL_VULKAN) { - // Apply rotation from the uniform. - WRITE(p, " mat2 displayRotation = mat2(\n"); - WRITE(p, " u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), u_rotation == 1.0 ? 1.0 : (u_rotation == 3.0 ? -1.0 : 0.0),\n"); - WRITE(p, " u_rotation == 3.0 ? 1.0 : (u_rotation == 1.0 ? -1.0 : 0.0), u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0)\n"); - WRITE(p, " );\n"); - - WRITE(p, " vec4 pos = position;\n"); - WRITE(p, " pos.xy = mul(displayRotation, pos.xy);\n"); - } else { - WRITE(p, " vec4 pos = position;\n"); - } - // The viewport is used in this case, so need to compensate for that. if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " vec4 outPos = depthRoundZVP(pos);\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(position);\n"); } else { - WRITE(p, " vec4 outPos = pos;\n"); + WRITE(p, " vec4 outPos = position;\n"); } } } else { @@ -1276,6 +1262,24 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } } + if (compat.shaderLanguage == GLSL_VULKAN && gstate_c.Use(GPU_USE_PRE_ROTATION)) { + // Apply rotation from the uniform. + WRITE(p, " mat2 displayRotation = mat2(\n"); + WRITE(p, " u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), u_rotation == 1.0 ? 1.0 : (u_rotation == 3.0 ? -1.0 : 0.0),\n"); + WRITE(p, " u_rotation == 3.0 ? 1.0 : (u_rotation == 1.0 ? -1.0 : 0.0), u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0)\n"); + WRITE(p, " );\n"); + + WRITE(p, " outPos.xy = mul(displayRotation, outPos.xy);\n"); + } + + bool flipY = strlen(compat.viewportYSign) > 0; + if (gstate_c.Use(GPU_USE_NONBUFFERED_FLIP)) { + flipY = !flipY; + } + if (flipY) { + WRITE(p, " outPos.y *= -1.0;\n"); + } + // We've named the output gl_Position in HLSL as well. WRITE(p, " %sgl_Position = outPos;\n", compat.vsOutPrefix); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 5dc9da2646ef..cc14e712f3a3 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -436,8 +436,8 @@ void DrawEngineD3D11::Flush() { SoftwareTransform swTransform(params); - const Lin::Vec3 trans(gstate_c.vpXOffset, -gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); - const Lin::Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); + const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); + const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 7a5c760f9b4f..4728c57083dd 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -387,8 +387,7 @@ void DrawEngineGLES::Flush() { const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset); const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale); - const bool invertedY = gstate_c.vpHeight * (params.flippedY ? 1.0 : -1.0f) < 0; - swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale); + swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result); // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 307ad5e1222e..c233d80e9740 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -190,6 +190,11 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_ROUND_DEPTH_TO_16BIT; } } + + if (g_Config.bSkipBufferEffects) { + features |= GPU_USE_NONBUFFERED_FLIP; + } + return features; } diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index e02aeced0b7d..6f8678675cc0 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -129,7 +129,6 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_depthRange, "u_depthRange" }); queries.push_back({ &u_cullRangeMin, "u_cullRangeMin" }); queries.push_back({ &u_cullRangeMax, "u_cullRangeMax" }); - queries.push_back({ &u_rotation, "u_rotation" }); // These two are only used for VR, but let's always query them for simplicity. queries.push_back({ &u_scaleX, "u_scaleX" }); @@ -309,20 +308,14 @@ static void SetMatrix4x3(GLRenderManager *render, GLint *uniform, const float *m render->SetUniformM4x4(uniform, m4x4); } -static inline void ScaleProjMatrix(Matrix4x4 &in, bool useBufferedRendering) { - float yOffset = gstate_c.vpYOffset; - if (!useBufferedRendering) { - // GL upside down is a pain as usual. - yOffset = -yOffset; - } - const Vec3 trans(gstate_c.vpXOffset, yOffset, gstate_c.vpZOffset); +static inline void ConvertProjMatrixToGL(Matrix4x4 &in) { + const Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset); const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale); in.translateAndScale(trans, scale); } -static inline void FlipProjMatrix(Matrix4x4 &in, bool useBufferedRendering) { - - const bool invertedY = useBufferedRendering ? (gstate_c.vpHeight < 0) : (gstate_c.vpHeight > 0); +static inline void FlipProjMatrix(Matrix4x4 &in) { + const bool invertedY = gstate_c.vpHeight < 0; if (invertedY) { in[1] = -in[1]; in[5] = -in[5]; @@ -435,8 +428,8 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin } UpdateVRParams(gstate.projMatrix); - FlipProjMatrix(vrProjection, useBufferedRendering); - ScaleProjMatrix(vrProjection, useBufferedRendering); + FlipProjMatrix(vrProjection); + ConvertProjMatrixToGL(vrProjection); render_->SetUniformM4x4(&u_proj_lens, vrProjection.m); } @@ -444,19 +437,14 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin Matrix4x4 flippedMatrix; memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); - FlipProjMatrix(flippedMatrix, useBufferedRendering); - ScaleProjMatrix(flippedMatrix, useBufferedRendering); + FlipProjMatrix(flippedMatrix); + ConvertProjMatrixToGL(flippedMatrix); render_->SetUniformM4x4(&u_proj, flippedMatrix.m); - render_->SetUniformF1(&u_rotation, useBufferedRendering ? 0 : (float)g_display.rotation); } if (dirty & DIRTY_PROJTHROUGHMATRIX) { Matrix4x4 proj_through; - if (useBufferedRendering) { - proj_through.setOrtho(0.0f, gstate_c.curRTWidth, 0.0f, gstate_c.curRTHeight, 0.0f, 1.0f); - } else { - proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0.0f, 0.0f, 1.0f); - } + proj_through.setOrthoGL(0.0f, gstate_c.curRTWidth, 0.0f, gstate_c.curRTHeight, 0.0f, 1.0f); render_->SetUniformM4x4(&u_proj_through, proj_through.getReadPtr()); } if (dirty & DIRTY_TEXENV) { diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 5ea181bd2945..35fc2054e883 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -68,7 +68,6 @@ class LinkedShader { int u_depthRange; // x,y = viewport xscale/xcenter. z,w=clipping minz/maxz (?) int u_cullRangeMin; int u_cullRangeMax; - int u_rotation; int u_mipBias; int u_scaleX; int u_scaleY; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 627a4c05c804..2bd79a088913 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -480,7 +480,8 @@ enum { GPU_USE_CLIP_DISTANCE = FLAG_BIT(24), GPU_USE_CULL_DISTANCE = FLAG_BIT(25), GPU_USE_SHADER_BLENDING = FLAG_BIT(26), // This is set to false when skip buffer effects is enabled and GPU_USE_FRAMEBUFFER_FETCH is not. - + GPU_USE_NONBUFFERED_FLIP = FLAG_BIT(27), // We use a flip hack to pretend the coordinate system is right-side-up, except if buffered rendering is off. + GPU_USE_PRE_ROTATION = FLAG_BIT(28), // VR flags (reserved or in-use) GPU_USE_VIRTUAL_REALITY = FLAG_BIT(29), GPU_USE_SINGLE_PASS_STEREO = FLAG_BIT(30), diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index a36f54c68c72..dd2db802bc6a 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -244,6 +244,10 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { break; } + if (vulkan->SupportsPreRotation() && g_Config.bSkipBufferEffects) { + features |= GPU_USE_PRE_ROTATION; + } + // Might enable this later - in the first round we are mostly looking at depth/stencil/discard. // if (!g_Config.bEnableVendorBugChecks) // features |= GPU_USE_ACCURATE_DEPTH; diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index b1d5abd8db26..20c5bbe299e2 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -152,7 +152,6 @@ class TextureCacheVulkan : public TextureCacheCommon { Path cbufferPath_; VulkanBuffer textureScaleCBuffer_; bool cbufferInited_ = true; - bool cbufferFailed_ = false; }; VkFormat getClutDestFormatVulkan(GEPaletteFormat format); diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 216c70d01ebe..73d83e184155 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -18,29 +18,132 @@ #include "ppsspp_config.h" #include "ext/xxhash.h" #include "Common/UI/UI.h" +#include "Common/UI/PopupScreens.h" #include "Common/Data/Text/I18n.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/File/FileUtil.h" +#include "Common/Net/HTTPClient.h" #include "Common/StringUtils.h" #include "Common/System/System.h" #include "Common/System/Request.h" -#include "Common/UI/PopupScreens.h" #include "Core/System.h" #include "Core/Config.h" #include "Core/CwCheat.h" #include "Core/MIPS/JitCommon/JitCommon.h" - +#undef new +#ifdef SYSTEM_RAPIDJSON +#include +#else +#include "ext/rapidjson/include/rapidjson/document.h" +#endif +#include "Common/DbgNew.h" #include "UI/GameInfoCache.h" #include "UI/CwCheatScreen.h" #include "UI/MiscViews.h" static const int FILE_CHECK_FRAME_INTERVAL = 53; +constexpr char g_cheatDBListUrl[] = "https://metadata.ppsspp.org/cheats.json"; + static Path GetGlobalCheatFilePath() { return GetSysDirectory(DIRECTORY_CHEATS) / "cheat.db"; } +struct CheatDatabaseDownloadInfo { + std::string name; + std::string maintainer; + std::string url; +}; + +// Use rapidjson to parse the cheat database list. +std::vector ParseJson(std::string_view json) { + rapidjson::Document d; + d.Parse(json.data(), json.size()); + + std::vector downloads; + + if (d.HasParseError()) { + ERROR_LOG(Log::CwCheats, "Failed to parse cheat database list: %.*s", STR_VIEW(json)); + return downloads; + } + if (!d.IsObject()) { + ERROR_LOG(Log::CwCheats, "1"); + return downloads; + } + if (!d.HasMember("databases") || !d["databases"].IsArray()) { + ERROR_LOG(Log::CwCheats, "databases is not an array"); + return downloads; + } + + const auto& dbs = d["databases"]; + for (auto& db : dbs.GetArray()) { + if (!db.IsObject()) + continue; + CheatDatabaseDownloadInfo info; + if (!db.HasMember("name") || !db["name"].IsString()) + continue; + info.name = db["name"].GetString(); + if (!db.HasMember("maintainer") || !db["maintainer"].IsString()) + continue; + info.maintainer = db["maintainer"].GetString(); + if (!db.HasMember("url") || !db["url"].IsString()) + continue; + info.url = db["url"].GetString(); + downloads.push_back(info); + } + return downloads; +} + +class CwCheatDownloadPopupScreen : public UI::PopupScreen { +public: + CwCheatDownloadPopupScreen(); + + void CreatePopupContents(UI::ViewGroup *parent) override; + void update() override; + + const char *tag() const override { return "CwCheatDownloadScreen"; } + + const std::string &ChosenUrl() const { return chosenUrl_; } + +private: + std::shared_ptr cheatsRequest_; + std::string chosenUrl_; + std::vector cheatDbs_; +}; + +CwCheatDownloadPopupScreen::CwCheatDownloadPopupScreen() : PopupScreen(T(I18NCat::DIALOG, "Back")) { + cheatsRequest_ = g_DownloadManager.StartDownload(g_cheatDBListUrl, Path(), http::RequestFlags::KeepInMemory, nullptr, "cheatdblist"); +} + +void CwCheatDownloadPopupScreen::update() { + UI::PopupScreen::update(); + if (cheatsRequest_ && cheatsRequest_->Done()) { + std::string data; + cheatsRequest_->buffer().TakeAll(&data); + cheatDbs_ = ParseJson(data); + cheatsRequest_.reset(); + RecreateViews(); + } +} + +void CwCheatDownloadPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { + using namespace UI; + auto cw = GetI18NCategory(I18NCat::CWCHEATS); + + if (File::Exists(GetGlobalCheatFilePath())) { + parent->Add(new NoticeView(NoticeLevel::WARN, cw->T("A cheat database already exists. Downloading a new one will overwrite it."), "")); + } + + for (auto &db : cheatDbs_) { + parent->Add(new Choice(db.name + " - " + db.maintainer, ImageID("I_DOWNLOAD")))->OnClick.Add([this, url = db.url](UI::EventParams &) { + INFO_LOG(Log::CwCheats, "Chosen cheat database URL: %s", url.c_str()); + chosenUrl_ = url; + TriggerFinish(DialogResult::DR_OK); + }); + } +} + CwCheatScreen::CwCheatScreen(const Path &gamePath) : UITwoPaneBaseDialogScreen(gamePath, TwoPaneFlags::Default) { } @@ -61,8 +164,7 @@ bool CwCheatScreen::TryLoadCheatInfo() { return false; } gameID = info->GetParamSFO().GetValueString("DISC_ID"); - if ((info->id.empty() || !info->disc_total) - && gamePath_.FilePathContainsNoCase("PSP/GAME/")) { + if ((info->id.empty() || !info->disc_total) && gamePath_.FilePathContainsNoCase("PSP/GAME/")) { gameID = g_paramSFO.GenerateFakeID(gamePath_); } @@ -100,6 +202,19 @@ bool CwCheatScreen::key(const KeyInput &input) { return UITwoPaneBaseDialogScreen::key(input); } +void CwCheatScreen::dialogFinished(const Screen *dialog, DialogResult result) { + if (auto downloadScreen = dynamic_cast(dialog)) { + if (downloadRequest_) { + ERROR_LOG(Log::CwCheats, "Download already in progress, ignoring new download request."); + return; + } + INFO_LOG(Log::CwCheats, "Starting download of cheat database from %s", downloadScreen->ChosenUrl().c_str()); + downloadRequest_ = g_DownloadManager.StartDownload(downloadScreen->ChosenUrl(), GetGlobalCheatFilePath(), http::RequestFlags::ProgressBar, nullptr, "cheatdbdownload"); + } else { + UITwoPaneBaseDialogScreen::dialogFinished(dialog, result); + } +} + void CwCheatScreen::CreateSettingsViews(UI::ViewGroup *leftColumn) { using namespace UI; auto cw = GetI18NCategory(I18NCat::CWCHEATS); @@ -109,6 +224,10 @@ void CwCheatScreen::CreateSettingsViews(UI::ViewGroup *leftColumn) { //leftColumn->Add(new Choice(cw->T("Add Cheat")))->OnClick.Handle(this, &CwCheatScreen::OnAddCheat); leftColumn->Add(new ItemHeader(cw->T("Import Cheats"))); + leftColumn->Add(new Choice(cw->T("Download cheat database")))->OnClick.Add([this](UI::EventParams &) { + screenManager()->push(new CwCheatDownloadPopupScreen()); + }); + Path cheatPath = GetGlobalCheatFilePath(); std::string root = GetSysDirectory(DIRECTORY_MEMSTICK_ROOT).ToString(); @@ -222,6 +341,16 @@ void CwCheatScreen::update() { fileCheckCounter_ = 0; } + if (downloadRequest_ && downloadRequest_->Done()) { + if (!downloadRequest_->Failed()) { + INFO_LOG(Log::CwCheats, "Cheat database downloaded successfully to %s.", GetGlobalCheatFilePath().ToVisualString().c_str()); + RecreateViews(); + } else { + ERROR_LOG(Log::CwCheats, "Failed to download cheat database"); + } + downloadRequest_.reset(); + } + UIBaseDialogScreen::update(); } @@ -313,7 +442,7 @@ void CwCheatScreen::OnImportBrowse(UI::EventParams ¶ms) { return; } Path path(value); - INFO_LOG(Log::System, "Attempting to load cheats from: '%s'", path.ToVisualString().c_str()); + INFO_LOG(Log::CwCheats, "Attempting to load cheats from: '%s'", path.ToVisualString().c_str()); int cheatsFound = 0; ImportAndReport(path); }); @@ -327,12 +456,12 @@ void CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { bool CwCheatScreen::ImportCheats(const Path &cheatFile, int *cheatsFound) { FILE *in = File::OpenCFile(cheatFile, "rt"); if (!in) { - WARN_LOG(Log::Common, "Unable to open %s\n", cheatFile.c_str()); + WARN_LOG(Log::CwCheats, "Unable to open %s\n", cheatFile.c_str()); return false; } if (gameID_.length() != 9 || !engine_) { - WARN_LOG(Log::Common, "CWCHEAT: Incorrect ID(%s) - can't import cheats.", gameID_.c_str()); + WARN_LOG(Log::CwCheats, "CWCHEAT: Incorrect ID(%s) - can't import cheats.", gameID_.c_str()); return false; } diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index 6922aa26b61d..84e2525bdc43 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -26,6 +26,7 @@ #include "UI/BaseScreens.h" #include "UI/SimpleDialogScreen.h" #include "UI/MiscViews.h" +#include "Common/Net/HTTPClient.h" struct CheatFileInfo; class CWCheatEngine; @@ -58,6 +59,8 @@ class CwCheatScreen : public UITwoPaneBaseDialogScreen { void CreateContentViews(UI::ViewGroup *) override; std::string_view GetTitle() const override; + void dialogFinished(const Screen *dialog, DialogResult result) override; + private: void OnCheckBox(int index); bool ImportCheats(const Path &cheatFile, int *cheatsFound); @@ -80,4 +83,6 @@ class CwCheatScreen : public UITwoPaneBaseDialogScreen { UI::ViewGroup *cheatList_ = nullptr; ViewSearch search_; + + std::shared_ptr downloadRequest_; }; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index cf9eaff5a18c..1d1891a169b5 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -488,6 +488,7 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) } System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED); + System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED); }); skipBufferEffects->SetDisabledPtr(&g_Config.bSoftwareRendering); diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 1cc1923ecaa3..271855fd7a3f 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -439,10 +439,6 @@ void NoticeView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec ApplyBoundBySpec(layoutWidth, horiz); const int align = wrapText_ ? FLAG_WRAP_TEXT : 0; MeasureNotice(dc, level_, text_, detailsText_, iconName_, align, layoutWidth, &w, &h, &height1_); - // Layout hack! Some weird problems with the layout that I can't figure out right now.. - if (squishy_) { - w = 50.0; - } } void NoticeView::Draw(UIContext &dc) { diff --git a/UI/SystemInfoScreen.cpp b/UI/SystemInfoScreen.cpp index 5822469c0f5d..b9f8f22e5777 100644 --- a/UI/SystemInfoScreen.cpp +++ b/UI/SystemInfoScreen.cpp @@ -504,10 +504,15 @@ void SystemInfoScreen::CreateVulkanExtsTab(UI::LinearLayout *gpuExtensions) { auto si = GetI18NCategory(I18NCat::SYSINFO); auto di = GetI18NCategory(I18NCat::DIALOG); + auto gr = GetI18NCategory(I18NCat::GRAPHICS); Draw::DrawContext *draw = screenManager()->getDrawContext(); CollapsibleSection *vulkanFeatures = gpuExtensions->Add(new CollapsibleSection(si->T("Vulkan Features"))); + + // TODO: This one belongs under its own header. And this is Vulkan "pre-rotation" really. + vulkanFeatures->Add(new InfoItem(gr->T("Display rotation"), StringFromFormat("%d°", (int)g_display.rotation * 90))); + std::vector features = draw->GetFeatureList(); for (const auto &feature : features) { vulkanFeatures->Add(new TextView(feature, FLAG_DYNAMIC_ASCII, true, new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); diff --git a/UI/UIAtlas.cpp b/UI/UIAtlas.cpp index 791c1d8fa697..c2ca1142d5cb 100644 --- a/UI/UIAtlas.cpp +++ b/UI/UIAtlas.cpp @@ -197,6 +197,7 @@ static const ImageMeta g_uiImageIDs[] = { {"I_ARCHIVE_ZIP", false}, {"I_ARCHIVE_7Z", false}, {"I_ARCHIVE_RAR", false}, + {"I_DOWNLOAD", false}, }; static std::string PNGNameFromID(std::string_view id) { diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index 08060967cee3..a1bc6178cab8 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -237,7 +237,7 @@ void SimpleGLWindow::DrawChecker() { const GLubyte indices[4] = {0,1,3,2}; Matrix4x4 ortho; - ortho.setOrtho(0, (float)w_, (float)h_, 0, -1, 1); + ortho.setOrthoGL(0, (float)w_, (float)h_, 0, -1, 1); glUniformMatrix4fv(drawProgram_->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); if (vao_) { glBufferData(GL_ARRAY_BUFFER, sizeof(pos) + sizeof(texCoords), nullptr, GL_DYNAMIC_DRAW); @@ -429,7 +429,7 @@ void SimpleGLWindow::Redraw(bool andSwap) { const float *texCoords = tflipped_ ? texCoordsFlipped : texCoordsNormal; Matrix4x4 ortho; - ortho.setOrtho(0, (float)w_, (float)h_, 0, -1, 1); + ortho.setOrthoGL(0, (float)w_, (float)h_, 0, -1, 1); glUniformMatrix4fv(drawProgram_->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); if (vao_) { glBufferData(GL_ARRAY_BUFFER, sizeof(pos) + sizeof(texCoordsNormal), nullptr, GL_DYNAMIC_DRAW); diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index eaf4fdc503b6..87304666c3a2 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -153,7 +153,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { }; Lin::Matrix4x4 ortho; - ortho.setOrtho(-(float)gstate_c.curRTOffsetX, (primaryWindow->TexWidth() - (int)gstate_c.curRTOffsetX) * scale[0], primaryWindow->TexHeight() * scale[1], 0, -1, 1); + ortho.setOrthoGL(-(float)gstate_c.curRTOffsetX, (primaryWindow->TexWidth() - (int)gstate_c.curRTOffsetX) * scale[0], primaryWindow->TexHeight() * scale[1], 0, -1, 1); glUniformMatrix4fv(previewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); if (previewVao != 0) { glBindVertexArray(previewVao); @@ -216,7 +216,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { } Lin::Matrix4x4 ortho; - ortho.setOrtho(0.0f - (float)gstate_c.curTextureXOffset * invRealTexWidth, 1.0f - (float)gstate_c.curTextureXOffset * invRealTexWidth, 1.0f - (float)gstate_c.curTextureYOffset * invRealTexHeight, 0.0f - (float)gstate_c.curTextureYOffset * invRealTexHeight, -1.0f, 1.0f); + ortho.setOrthoGL(0.0f - (float)gstate_c.curTextureXOffset * invRealTexWidth, 1.0f - (float)gstate_c.curTextureXOffset * invRealTexWidth, 1.0f - (float)gstate_c.curTextureYOffset * invRealTexHeight, 0.0f - (float)gstate_c.curTextureYOffset * invRealTexHeight, -1.0f, 1.0f); glUniformMatrix4fv(texPreviewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); if (texPreviewVao != 0) { glBindVertexArray(texPreviewVao); diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index ed8a0029ef36..3f62b6e38319 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -1185,6 +1185,7 @@ true true + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 4bc460a74415..40ca4d963758 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -845,6 +845,9 @@ assets + + assets + diff --git a/assets/cheats.json b/assets/cheats.json new file mode 100644 index 000000000000..39711f8053f3 --- /dev/null +++ b/assets/cheats.json @@ -0,0 +1,9 @@ +{ + "databases": [ + { + "name": "CWCheat-Database-Plus", + "maintainer": "Saramagrean", + "url": "https://raw.githubusercontent.com/Saramagrean/CWCheat-Database-Plus-/refs/heads/master/cheat.db" + } + ] +} diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 07f5df38f5cf..2b8f3bc24bf4 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -203,8 +203,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = قاعدة بيانات الغش موجودة بالفعل. تنزيل جديدة سيؤدي إلى استبدالها. # AI translated Added %1 cheats for this game = تمت إضافة %1 غش لهذه اللعبة # AI translated Cheats = ‎الغش +Download cheat database = قم بتنزيل قاعدة بيانات الغش # AI translated Edit Cheat File = ‎عدل ملف الغش Import Cheats = ‎إستورد من cheat.db Import from %s = ‎إستورد من %s diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 85224b8cdac5..e922ae9ea3ac 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Artıq bir fırıldaq verilənlər bazası mövcuddur. Yeni birini yükləmək onu əvəz edəcək. # AI translated Added %1 cheats for this game = %1 kod oyuna əlavə edildi # AI translated Cheats = Hiylələr +Download cheat database = Davam et edin cheat verilənlər bazası # AI translated Edit Cheat File = Hiylə faylını düzəlt Import Cheats = Cheat.db'dən götür Import from %s = %s yerindən götür diff --git a/assets/lang/be_BY.ini b/assets/lang/be_BY.ini index 370764210f12..b050790e7b0d 100644 --- a/assets/lang/be_BY.ini +++ b/assets/lang/be_BY.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = База дадзеных чыт-кода ўжо існуе. Спампоўка новай зьменіць яе. # AI translated Added %1 cheats for this game = Дададзена %1 чыт для гэтай гульні # AI translated Cheats = Чыты +Download cheat database = Скачайце базу даных чыт # AI translated Edit Cheat File = Рэдагаваць файл чытаў Import Cheats = Імпарт з cheat.db Import from %s = Імпарт з %s diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 069dc6c1b4e3..1cbbe17765f7 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Базата с кодове вече съществува. Изтеглянето на нова ще я замени. # AI translated Added %1 cheats for this game = Добавени са %1 чийтове за тази игра # AI translated Cheats = Чийтове +Download cheat database = Изтеглете базата данни с трикове # AI translated Edit Cheat File = Редактиране на чийтове файл Import Cheats = Внеси от cheat.db Import from %s = Внеси от %s diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 893748f4c575..1daf258d4b72 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Ja existeix una base de dades de trucs. Descarregar-ne una nova la sobrescriurà. # AI translated Added %1 cheats for this game = S'han afegit %1 trucs per a aquest joc # AI translated Cheats = Trucs +Download cheat database = Descarrega la base de dades de trics # AI translated Edit Cheat File = Editar el fitxer de trucs Import Cheats = Importar «cheat.db» Import from %s = Importar %s diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 4ab350291393..2d137701cde4 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Databáze cheatů již existuje. Stáhnutí nové ji přepíše. # AI translated Added %1 cheats for this game = Přidáno %1 cheatů pro tuto hru # AI translated Cheats = Cheaty +Download cheat database = Stáhnout databázi cheatů # AI translated Edit Cheat File = Upravit soubor s cheaty Import Cheats = Importovat z cheat.db Import from %s = Importovat z %s diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index dd3d9b99ecb8..1297c309b595 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = En snyde-database eksisterer allerede. Download af en ny vil overskrive den. # AI translated Added %1 cheats for this game = Tilføjet %1 snyd til dette spil # AI translated Cheats = Snyd +Download cheat database = Download cheat-database # AI translated Edit Cheat File = Editer snydefil Import Cheats = Import from cheat.db Import from %s = Importer fra %s diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index ef3f035b67a5..9d3c51975316 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Eine Cheat-Datenbank existiert bereits. Das Herunterladen einer neuen wird sie überschreiben. # AI translated Added %1 cheats for this game = Es wurden %1 Cheats für dieses Spiel hinzugefügt # AI translated Cheats = Cheats +Download cheat database = Cheat-Datenbank herunterladen # AI translated Edit Cheat File = Cheat-Datei ändern Import Cheats = Cheats importieren (aus cheat.db) Import from %s = Importieren von %s diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index a2de31394e05..c0290b7928a0 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Database cheat sudah ada. Mengunduh yang baru akan menimpanya. # AI translated Added %1 cheats for this game = Ditambahkan %1 cheat untuk game ini # AI translated Cheats = Cheat +Download cheat database = Unduh database cheat # AI translated Edit Cheat File = Edit cheat file Import Cheats = Patamanni cheat.db Import from %s = Patamanni %s diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index e7f6e6f17255..f60c941f47a7 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -219,8 +219,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = A cheat database already exists. Downloading a new one will overwrite it. Added %1 cheats for this game = Added %1 cheats for this game Cheats = Cheats +Download cheat database = Download cheat database Edit Cheat File = Edit cheat file Import Cheats = Import from cheat.db Import from %s = Import from %s diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 7d6d38d95d55..e983e385c321 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -196,8 +196,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Ya existe una base de datos de trucos. Descargar una nueva la sobrescribirá. # AI translated Added %1 cheats for this game = Añadidos %1 trucos para este juego # AI translated Cheats = Trucos +Download cheat database = Descargar base de datos de trampas # AI translated Edit Cheat File = Editar archivo de trucos Import Cheats = Importar archivo cheat.db Import from %s = Importar desde %s diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 20c8717f4784..dbf3cb31521a 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Ya existe una base de datos de trucos. Descargar una nueva la sobrescribirá. # AI translated Added %1 cheats for this game = Se añadieron %1 trucos para este juego # AI translated Cheats = Trucos +Download cheat database = Descargar base de datos de trucos # AI translated Edit Cheat File = Editar archivo de trucos Import Cheats = Importar archivo cheat.db Import from %s = Importar desde %s diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 85438f61e143..5c8373f8e7b0 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = یک پایگاه داده تقلب already موجود است. دانلود یک پایگاه داده جدید آن را جایگزین خواهد کرد. # AI translated Added %1 cheats for this game = به این بازی %1 تقلب اضافه شد # AI translated Cheats = ‎کد‌های تقلب +Download cheat database = دانلود پایگاه داده تقلب # AI translated Edit Cheat File = ‎ویرایش فایل کد‌ها Import Cheats = ‎cheat.db وارد کردن از Import from %s = وارد کردن از %s diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index ade2033d8d0d..0241885b079d 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Huijaustietokanta on jo olemassa. Uuden lataaminen korvasi sen. # AI translated Added %1 cheats for this game = Lisätty %1 koodia tälle pelille # AI translated Cheats = Huijaukset +Download cheat database = Lataa huijaustietokanta # AI translated Edit Cheat File = Muokkaa huijaustiedostoa Import Cheats = Tuo huijauksia Import from %s = %s diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 00aa139db12f..8efc6ec288ab 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -219,8 +219,10 @@ X = Axe X Y = Axe Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Une base de données de triches existe déjà. Télécharger une nouvelle l'écrasera. # AI translated Added %1 cheats for this game = Ajout de %1 astuces pour ce jeu # AI translated Cheats = Codes de triche +Download cheat database = Télécharger la base de données de triche # AI translated Edit Cheat File = Modifier le fichier de triche Import Cheats = Importer des codes de triche Import from %s = Importer de %s diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 61cc2cede23f..2b3f1e598a50 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Xa existe unha base de datos de trampas. Descargar unha nova sobrescribirá a existente. # AI translated Added %1 cheats for this game = Engadidos %1 trucos para este xogo # AI translated Cheats = Trucos +Download cheat database = Descarga a base de datos de trucos # AI translated Edit Cheat File = Editar arquivo de trucos Import Cheats = Importar cheat.db Import from %s = Importar %s diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index aa6f32561736..d3ddeba23f7c 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Μια βάση δεδομένων cheat υπάρχει ήδη. Η λήψη μιας νέας θα την αντικαταστήσει. # AI translated Added %1 cheats for this game = Προστέθηκαν %1 cheats για αυτό το παιχνίδι # AI translated Cheats = Κωδικοί +Download cheat database = Κατεβάστε τη βάση δεδομένων cheat # AI translated Edit Cheat File = Επεξεργασία αρχείου κωδικών Import Cheats = Εισαγωγή από cheat.db Import from %s = Εισαγωγή από %s diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 1dea18bfc64c..3ade3a70b25d 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = מאגר נתוני רמאות קיים כבר. הורדת אחד חדש תחליף אותו. # AI translated Added %1 cheats for this game = הוספו %1 קודי רמאות למשחק הזה # AI translated Cheats = Cheats +Download cheat database = הורד את מסד הנתונים של ההונאות # AI translated Edit Cheat File = Edit cheat file Import Cheats = Import from cheat.db Import from %s = Import from %s diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 54d2e46d1480..16a70df8f2e6 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = מאגר נתוני רמאות קיים כבר. הורדת אחד חדש תחליף אותו. # AI translated Added %1 cheats for this game = המשחק הזה קיבל %1 קודי רמאות # AI translated Cheats = Cheats +Download cheat database = שדר מסד הנתונים של ההונאות # AI translated Edit Cheat File = Edit cheat file Import Cheats = Import from cheat.db Import from %s = Import from %s diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index af9f61ce50ba..ff5f4551420b 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Baza podataka o prevarama već postoji. Preuzimanje nove će je prebrisati. # AI translated Added %1 cheats for this game = Dodano %1 varanja za ovu igru # AI translated Cheats = Šifre +Download cheat database = Preuzmi bazu podataka s podvalama # AI translated Edit Cheat File = Izmijeni cheat datoteku Import Cheats = Uvezi iz cheat.db Import from %s = Uvezi iz %s diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 7bb97b7c2199..6384a42a1efe 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = A csalás adatbázis már létezik. Egy új letöltése felülírja ezt. # AI translated Added %1 cheats for this game = %1 csalást adtunk hozzá ehhez a játékhoz # AI translated Cheats = Csalások +Download cheat database = Töltse le a csalás adatbázist # AI translated Edit Cheat File = Csalás fájl szerkesztése Import Cheats = Importálás cheat.db-ből Import from %s = Importálás innen: %s diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 8d79c1950aa9..50aea553e7fa 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Database kecurangan sudah ada. Mengunduh yang baru akan menimpanya. # AI translated Added %1 cheats for this game = Ditambahkan %1 cheat untuk permainan ini # AI translated Cheats = Cheat +Download cheat database = Unduh basis data cheat # AI translated Edit Cheat File = Edit berkas cheat Import Cheats = Impor dari cheat.db Import from %s = Impor dari %s diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 1737c8e2d5dd..93acd4f2920b 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Esiste già un database di trucchi. Scaricare uno nuovo lo sovrascriverà. # AI translated Added %1 cheats for this game = Aggiunti %1 trucchi per questo gioco # AI translated Cheats = Trucchi +Download cheat database = Scarica il database dei cheat # AI translated Edit Cheat File = Modifica file Trucchi Import Cheats = Importa da cheat.db Import from %s = Importa da %s diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 0e14c663056d..668ede31987c 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = チートデータベースはすでに存在します。新しいものをダウンロードすると上書きされます。 # AI translated Added %1 cheats for this game = このゲームに%1 チートが追加されました # AI translated Cheats = チート +Download cheat database = チートデータベースをダウンロード # AI translated Edit Cheat File = チートファイルを編集する Import Cheats = cheat.dbからインポートする Import from %s = %sからインポートする diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index cc255e4d6cd4..f9bce51608da 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Database curang wis ana. Ngundhuh anyar bakal ngowahi. # AI translated Added %1 cheats for this game = Dianyari %1 curang kanggo game iki # AI translated Cheats = Mbeling +Download cheat database = Download database cheat # AI translated Edit Cheat File = Sunting berkas mbeling Import Cheats = Import from cheat.db Import from %s = Njokot soko %s diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 2c321d9d0bea..ca855d8a9faa 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = 치트 데이터베이스가 이미 존재합니다. 새로 다운로드하면 덮어쓰게 됩니다. # AI translated Added %1 cheats for this game = 이 게임에 %1 치트가 추가되었습니다 # AI translated Cheats = 치트 +Download cheat database = 치트 데이터베이스 다운로드 # AI translated Edit Cheat File = 치트 파일 수정 Import Cheats = cheat.db에서 가져오기 Import from %s = %s에서 가져오기 diff --git a/assets/lang/ku_SO.ini b/assets/lang/ku_SO.ini index e1542ef704a0..13fdb8d9b018 100644 --- a/assets/lang/ku_SO.ini +++ b/assets/lang/ku_SO.ini @@ -208,8 +208,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Danezana cheat heye. Daneyek nû dakêşan wê ew lê bigire. # AI translated Added %1 cheats for this game = Lihevhatin %1 tîkîne ji bo vê lîstikê # AI translated Cheats = Cheats +Download cheat database = Download cheat database # AI translated Edit Cheat File = Edit cheat file Import Cheats = Import from cheat.db Import from %s = Import from %s diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 4669cf22cb23..7977e1426e82 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = ລົບລູກວິທີບໍ່ມີໃບອະທິບາຍແລ້ວ. ການດາວໂອນໃໝ່ຈະປ່ອນໃຫມ່. # AI translated Added %1 cheats for this game = ເພີ່ມເຂົ້າແບບ %1 ສໍາລັບເກมນີ້ # AI translated Cheats = ການໃຊ້ສູດໂກງ +Download cheat database = ດາວ໌ໍ່ສູງປະເພດຂອງຄອບຂໍ້ມູນ # AI translated Edit Cheat File = ປັບແຕ່ງໄຟລ໌ສູດໂກງ Import Cheats = Import from cheat.db Import from %s = ນຳເຂົ້າຈາກໄຟລ໌ສູດໂກງ %s diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 48627630d994..80c955f756cb 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Apgaulės duomenų bazė jau egzistuoja. Atsisiųsti naują ją perrašys. # AI translated Added %1 cheats for this game = Pridėta %1 sukčiavimų šiai žaidimui # AI translated Cheats = Kodai +Download cheat database = Atsisiųsti apgaulės duomenų bazę # AI translated Edit Cheat File = Redaguoti kodų failą Import Cheats = Importuoti iš cheat.db Import from %s = Importuoti iš %s diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 41fccf97e774..3e679dc3196b 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Pangkalan data penipuan sudah ada. Memuat turun yang baru akan menimpanya. # AI translated Added %1 cheats for this game = Ditambahkan %1 helah untuk permainan ini # AI translated Cheats = Cheat +Download cheat database = Muat turun pangkalan data cheat # AI translated Edit Cheat File = Ubah cheat file Import Cheats = Import dari cheat.db Import from %s = Import dari %s diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 88bcc8d34c3b..aa0f2a678d8d 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Een cheat-database bestaat al. Het downloaden van een nieuwe zal deze overschrijven. # AI translated Added %1 cheats for this game = Toegevoegd %1 cheats voor dit spel # AI translated Cheats = Cheats +Download cheat database = Download cheat-database # AI translated Edit Cheat File = Cheatbestand bewerken Import Cheats = Importeren van cheat.db Import from %s = Importeren van %s diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index e8027f7bed3d..740615776976 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = En juksedatabase finnes allerede. Nedlasting av en ny vil overskrive den. # AI translated Added %1 cheats for this game = Lagt til %1 jukse for dette spillet # AI translated Cheats = Cheats +Download cheat database = Last ned juksedatabase # AI translated Edit Cheat File = Edit cheat file Import Cheats = Import from cheat.db Import from %s = Import from %s diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index e73a4fc16172..bde823aae0bc 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Baza danych cheatu już istnieje. Pobranie nowej ją nadpisze. # AI translated Added %1 cheats for this game = Dodano %1 cheatów do tej gry # AI translated Cheats = Kody +Download cheat database = Pobierz bazę danych oszustw # AI translated Edit Cheat File = Edytuj plik kodów Import Cheats = Importuj z pliku cheat.db Import from %s = Importuj z pliku %s diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 6828b263e729..ac7bf3881117 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -219,8 +219,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Uma base de dados de cheats já existe. Baixar uma nova a substituirá. # AI translated Added %1 cheats for this game = Adicionou %1 trapaças pra este jogo Cheats = Trapaças +Download cheat database = Baixar banco de dados de trapaças # AI translated Edit Cheat File = Editar arquivo de trapaças Import Cheats = Importar do cheat.db Import from %s = Importar do %s diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index eccab803cb7e..27aa60d51a67 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -219,8 +219,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Uma base de dados de cheats já existe. Baixar uma nova sobrescrevê-la-á. # AI translated Added %1 cheats for this game = Adicionados %1 cheats para este jogo # AI translated Cheats = Cheats +Download cheat database = Descarregar base de dados de truques # AI translated Edit Cheat File = Editar ficheiro de Cheats Import Cheats = Importar de cheat.db Import from %s = Importar de %s diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index eab75511280c..7765f0686b2c 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = O bază de date cu cheats există deja. Descărcarea uneia noi o va suprascrie. # AI translated Added %1 cheats for this game = Adăugate %1 cheats pentru acest joc # AI translated Cheats = Trișare +Download cheat database = Descărcați baza de date pentru cheat-uri # AI translated Edit Cheat File = Editare fișier trișare Import Cheats = Importă din cheat.db #Import %s = Importă din %s diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 71cd83897154..54a78243be4f 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = База данных чит-кодов уже существует. Загрузка новой перезапишет её. # AI translated Added %1 cheats for this game = Добавлено %1 читов для этой игры Cheats = Читы +Download cheat database = Скачать базу данных читов # AI translated Edit Cheat File = Изменить файл чита Import Cheats = Импортировать из cheat.db Import from %s = Импортировать из %s diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 9c037023f38e..e1d6f6712216 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = En fus database finns redan. Nedladdning av en ny kommer att skriva över den. # AI translated Added %1 cheats for this game = Lade till %1 fusk för det här spelet Cheats = Fusk +Download cheat database = Ladda ner fuskdatabas # AI translated Edit Cheat File = Redigera fuskfil Import Cheats = Importera från cheat.db Import from %s = Importera från %s diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index d767e717ab23..ebc8fc4ad6c6 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Маъхазаи хидоят аллакай мавҷуд аст. Иқтибос кардани нав онро иваз мекунад. # AI translated Added %1 cheats for this game = Эҳтимолҳои %1 барои ин бозӣ илова карда шуданд # AI translated Cheats = Mga Daya +Download cheat database = Загрузить базу данных для обмана # AI translated Edit Cheat File = I-edit ang Cheat File Import Cheats = I-import ang mga daya mula sa cheat.db Import from %s = I-Import ang mga daya mula sa %s diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 2b2cacc97e07..c421c0601907 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -195,8 +195,10 @@ X = แกน X Y = แกน Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = ฐานข้อมูลการโกงมีอยู่แล้ว การดาวน์โหลดใหม่จะเขียนทับมัน. # AI translated Added %1 cheats for this game = เพิ่ม %1 สูตรโกงสำหรับเกมนี้ Cheats = การใช้สูตรโกง +Download cheat database = ดาวน์โหลดฐานข้อมูลโกง # AI translated Edit Cheat File = ปรับแต่งไฟล์สูตรโกง Import Cheats = นำเข้าจากไฟล์สูตรโกง Import from %s = นำเข้าจาก %s diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 5ccc123f34cf..66a379b7eeb9 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Bir hile veritabanı zaten var. Yeni bir indirmek onu üzerine yazacaktır. # AI translated Added %1 cheats for this game = Bu oyun için %1 hile eklendi # AI translated Cheats = Hileler +Download cheat database = Hile veritabanını indir # AI translated Edit Cheat File = Hile Dosyası Düzenle Import Cheats = Hileleri İçe Aktar Import from %s = Şuradan Aktar %s diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index bb0a2a2c17bb..eda0d05ed883 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = База даних читів вже існує. Завантаження нової перепише її. # AI translated Added %1 cheats for this game = Додано %1 читів для цієї гри # AI translated Cheats = Чіт-коди +Download cheat database = Скачати базу даних чітів # AI translated Edit Cheat File = Змінити файл чіт-коду Import Cheats = Імпортувати з cheat.db Import from %s = Імпортувати з %s diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 78df78aee906..11873c79bde7 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = Một cơ sở dữ liệu gian lận đã tồn tại. Tải xuống một cái mới sẽ ghi đè nó. # AI translated Added %1 cheats for this game = Đã thêm %1 mã gian lận cho trò chơi này # AI translated Cheats = Cheats +Download cheat database = Tải về cơ sở dữ liệu cheat # AI translated Edit Cheat File = Sửa mục cheat Import Cheats = Nhập mã từ cheat.db Import from %s = Nhập mã từ %s diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 5498eb00cf1f..efed768b1f9f 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = 作弊数据库已经存在。下载新版本将覆盖它。 # AI translated Added %1 cheats for this game = 为此游戏添加了 %1 作弊码 # AI translated Cheats = 金手指 +Download cheat database = 下载作弊数据库 # AI translated Edit Cheat File = 编辑金手指文件 Import Cheats = 从cheat.db导入 Import from %s = 从%s导入 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 937b29b3ed54..46c4c1d39191 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -195,8 +195,10 @@ X = X Y = Y [CwCheats] +A cheat database already exists. Downloading a new one will overwrite it. = 作弊數據庫已經存在。下載新的將覆蓋它。 # AI translated Added %1 cheats for this game = 為此遊戲添加了 %1 作弊碼 # AI translated Cheats = 密技 +Download cheat database = 下載作弊資料庫 # AI translated Edit Cheat File = 編輯密技檔案 Import Cheats = 從 cheat.db 匯入 Import from %s = 從 %s 匯入 diff --git a/assets/ui_images/images.svg b/assets/ui_images/images.svg index 8b1ecbdcb3d8..13b8100a8d86 100644 --- a/assets/ui_images/images.svg +++ b/assets/ui_images/images.svg @@ -23,9 +23,9 @@ inkscape:pagecheckerboard="true" inkscape:deskcolor="#d1d1d1" inkscape:document-units="px" - inkscape:zoom="4" - inkscape:cx="361.75" - inkscape:cy="499.625" + inkscape:zoom="5.6568542" + inkscape:cx="331.63308" + inkscape:cy="448.74764" inkscape:window-width="3840" inkscape:window-height="2071" inkscape:window-x="-9" @@ -125,7 +125,7 @@ transform="matrix(0.51483133,0,0,0.48865723,85.611849,129.89633)" aria-label="SD" />