From 120d279213c6789d4a2fc1369edbf9592b48636e Mon Sep 17 00:00:00 2001 From: Douglas Teles Date: Tue, 23 Jun 2026 14:22:31 -0300 Subject: [PATCH] Sync standalone + libretro emulator fixes from ROCKNIX retroarch: bump to commit bdba046f (v1.22.2 + fixes) and rebase the two local patches (0010-paths, 0011-cheevos-sounds) so they apply cleanly against the new tree. setsettings.sh: configure_hotkeys now detects the InputPlumber-emulated DualSense pad first, then falls back to js0 / joypad. Without this, retroarch took the raw event device and the hotkey binding never matched what InputPlumber actually exposed to userspace. drastic-sa: pull the new libdrastouch (sharp-shimmerless + quilez pixel shaders, SDL2 hook) and the matching start_drastic.sh, which now reads the shader setting and exports DSHOOK_SHADER. Drops the dead S922X libmali block we never executed on RK3326. hypseus-singe: rewrite of start_hypseus.sh fixes broken controls (autoconfig.cfg lookup was matching too loosely) and adds the set_kill on exit so the quit hotkey actually terminates the emulator instead of leaving it parented to ES. ppsspp-sa: add 005-hide-unsupported-ui-items.patch to drop the "www.ppsspp.org" link and the "Buy PPSSPP Gold" button from the main screen. Handheld UX cleanup, no behavioral change. Co-Authored-By: Claude Opus 4.7 --- .../archr/sources/scripts/setsettings.sh | 6 +- .../emulators/libretro/retroarch/package.mk | 2 +- .../retroarch/patches/0010-paths.patch | 16 +- .../patches/0011-cheevos-sounds.patch | 10 +- .../drastic-sa/scripts/start_drastic.sh | 15 +- .../drastic-sa/sources/libdrastouch.c | 545 +++++++++++++++++- .../hypseus-singe/sources/start_hypseus.sh | 34 +- .../005-hide-unsupported-ui-items.patch | 87 +++ 8 files changed, 654 insertions(+), 61 deletions(-) create mode 100644 projects/ArchR/packages/emulators/standalone/ppsspp-sa/patches/005-hide-unsupported-ui-items.patch diff --git a/projects/ArchR/packages/archr/sources/scripts/setsettings.sh b/projects/ArchR/packages/archr/sources/scripts/setsettings.sh index 3425b997e1..9c2a334e32 100755 --- a/projects/ArchR/packages/archr/sources/scripts/setsettings.sh +++ b/projects/ArchR/packages/archr/sources/scripts/setsettings.sh @@ -348,7 +348,11 @@ EOF function configure_hotkeys() { log "Configure hotkeys..." local MY_CONTROLLER - if grep -q "js0" /proc/bus/input/devices; then + + if grep -q "Sony Interactive Entertainment DualSense Wireless Controller" /proc/bus/input/devices; then + # InputPlumber virtual DS5 + MY_CONTROLLER="Sony Interactive Entertainment DualSense Wireless Controller" + elif grep -q "js0" /proc/bus/input/devices; then MY_CONTROLLER=$(grep -b4 js0 /proc/bus/input/devices | awk 'BEGIN {FS="\""}; /Name/ {printf $2}') else MY_CONTROLLER=$(grep -b4 joypad /proc/bus/input/devices | awk 'BEGIN {FS="\""}; /Name/ {printf $2}') diff --git a/projects/ArchR/packages/emulators/libretro/retroarch/package.mk b/projects/ArchR/packages/emulators/libretro/retroarch/package.mk index 4b18fb3690..27e2a4418d 100644 --- a/projects/ArchR/packages/emulators/libretro/retroarch/package.mk +++ b/projects/ArchR/packages/emulators/libretro/retroarch/package.mk @@ -3,7 +3,7 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="retroarch" -PKG_VERSION="fae7468de15b32a0e105e45325e5ca85e62ea7d4" # v1.22.2 + fixes +PKG_VERSION="bdba046fa6766380bc2457532f38e589df769aaf" # v1.22.2 + fixes PKG_SITE="https://github.com/libretro/RetroArch" PKG_URL="${PKG_SITE}/archive/${PKG_VERSION}.tar.gz" PKG_LICENSE="GPLv3" diff --git a/projects/ArchR/packages/emulators/libretro/retroarch/patches/0010-paths.patch b/projects/ArchR/packages/emulators/libretro/retroarch/patches/0010-paths.patch index 75595787dc..e3d691ed7f 100644 --- a/projects/ArchR/packages/emulators/libretro/retroarch/patches/0010-paths.patch +++ b/projects/ArchR/packages/emulators/libretro/retroarch/patches/0010-paths.patch @@ -1,8 +1,8 @@ diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c -index e1db1da096..7baf8a5f21 100644 +index 1fcf97e507..17d1a10a40 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c -@@ -1812,7 +1812,7 @@ static void frontend_unix_get_env(int *argc, +@@ -2018,7 +2018,7 @@ static void frontend_unix_get_env(int *argc, "/usr/share/games/retroarch", "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); else @@ -11,23 +11,23 @@ index e1db1da096..7baf8a5f21 100644 "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); #if defined(DINGUX) -@@ -1885,7 +1885,7 @@ static void frontend_unix_get_env(int *argc, +@@ -2091,7 +2091,7 @@ static void frontend_unix_get_env(int *argc, fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], "remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], base_path, -+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], "/tmp/", ++ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], "/tmp/", "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG], base_path, "records_config", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG])); -@@ -1896,14 +1896,14 @@ static void frontend_unix_get_env(int *argc, +@@ -2102,14 +2102,14 @@ static void frontend_unix_get_env(int *argc, libretro_database_directory, sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); else - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], base_path, + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], "/tmp/", "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); - if (!string_is_empty(libretro_video_shader_directory)) + if (libretro_video_shader_directory && *libretro_video_shader_directory) strlcpy(g_defaults.dirs[DEFAULT_DIR_SHADER], libretro_video_shader_directory, sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); @@ -35,9 +35,9 @@ index e1db1da096..7baf8a5f21 100644 - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], base_path, + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], "/tmp/", "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); - if (!string_is_empty(libretro_cheats_directory)) + if (libretro_cheats_directory && *libretro_cheats_directory) strlcpy(g_defaults.dirs[DEFAULT_DIR_CHEATS], -@@ -1912,9 +1912,9 @@ static void frontend_unix_get_env(int *argc, +@@ -2118,9 +2118,9 @@ static void frontend_unix_get_env(int *argc, else fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS], base_path, "cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); diff --git a/projects/ArchR/packages/emulators/libretro/retroarch/patches/0011-cheevos-sounds.patch b/projects/ArchR/packages/emulators/libretro/retroarch/patches/0011-cheevos-sounds.patch index b5e8662091..619abb75ae 100644 --- a/projects/ArchR/packages/emulators/libretro/retroarch/patches/0011-cheevos-sounds.patch +++ b/projects/ArchR/packages/emulators/libretro/retroarch/patches/0011-cheevos-sounds.patch @@ -1,8 +1,8 @@ diff --git a/audio/audio_driver.c b/audio/audio_driver.c -index 01a727eb95..fc43700d22 100644 +index d5cabac95b..caa992381c 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c -@@ -1339,8 +1339,8 @@ static void audio_driver_load_menu_bgm_callback(retro_task_t *task, +@@ -1569,8 +1569,8 @@ static void audio_driver_load_menu_bgm_c void audio_driver_load_system_sounds(void) { char basename_noext[NAME_MAX_LENGTH]; @@ -13,7 +13,7 @@ index 01a727eb95..fc43700d22 100644 settings_t *settings = config_get_ptr(); const char *dir_assets = settings->paths.directory_assets; const bool audio_enable_menu = settings->bools.audio_enable_menu; -@@ -1365,19 +1365,6 @@ void audio_driver_load_system_sounds(void) +@@ -1597,19 +1597,6 @@ void audio_driver_load_system_sounds(voi if (!audio_enable_menu && !audio_enable_cheevo_unlock) goto end; @@ -33,10 +33,10 @@ index 01a727eb95..fc43700d22 100644 list = dir_list_new(sounds_path, MENU_SOUND_FORMATS, false, false, false, false); list_fallback = dir_list_new(sounds_fallback_path, MENU_SOUND_FORMATS, false, false, false, false); -@@ -1423,8 +1410,13 @@ void audio_driver_load_system_sounds(void) - path_notice_back = path; +@@ -1660,8 +1647,13 @@ void audio_driver_load_system_sounds(voi else if (string_is_equal_noncase(basename_noext, "bgm")) path_bgm = path; + #endif - else if (string_is_equal_noncase(basename_noext, "unlock")) - path_cheevo_unlock = path; + else if(string_is_empty(settings->arrays.cheevos_unlock_sound) == false) { diff --git a/projects/ArchR/packages/emulators/standalone/drastic-sa/scripts/start_drastic.sh b/projects/ArchR/packages/emulators/standalone/drastic-sa/scripts/start_drastic.sh index 6d2bd390f1..e8f59657ea 100644 --- a/projects/ArchR/packages/emulators/standalone/drastic-sa/scripts/start_drastic.sh +++ b/projects/ArchR/packages/emulators/standalone/drastic-sa/scripts/start_drastic.sh @@ -17,6 +17,7 @@ HIRES3D=$(get_setting hires_3d "${PLATFORM}" "${GAME}") THREADED3D=$(get_setting threaded_3d "${PLATFORM}" "${GAME}") FOLLOW3D=$(get_setting follow_3d_renderer "${PLATFORM}" "${GAME}") MICTHRESH=$(get_setting microphone_sensitivity "${PLATFORM}" "${GAME}") +SHADER=$(get_setting shader "${PLATFORM}" "${GAME}") #load gptokeyb support files control-gen_init.sh @@ -82,21 +83,11 @@ fi cd /storage/.config/drastic/ @HOTKEY@ -# Fix for libmali gpu driver on S922X platform -if [ "${HW_DEVICE}" = "S922X" ]; then - GPUDRIVER=$(/usr/bin/gpudriver) - - if [ "${GPUDRIVER}" = "libmali" ]; then - export SDL_VIDEO_GL_DRIVER=\/usr\/lib\/egl\/libGL.so.1 - export SDL_VIDEO_EGL_DRIVER=\/usr\/lib\/egl\/libEGL.so.1 - fi -fi - $GPTOKEYB "drastic" -c "drastic.gptk" & # Fix actual touch inputs by replacing touch->mouse translation and add hw mic support export LD_PRELOAD="/usr/lib/libdrastouch.so" export SDL_TOUCH_MOUSE_EVENTS="0" export DSHOOK_MIC_THRESH="${MICTHRESH}" +export DSHOOK_SHADER="${SHADER:-none}" ./drastic "$1" -_gptokeyb_pid="$(pidof gptokeyb 2>/dev/null)" -[ -n "${_gptokeyb_pid}" ] && kill -9 ${_gptokeyb_pid} +kill -9 $(pidof gptokeyb) diff --git a/projects/ArchR/packages/emulators/standalone/drastic-sa/sources/libdrastouch.c b/projects/ArchR/packages/emulators/standalone/drastic-sa/sources/libdrastouch.c index 790923bca9..1cef5e1be6 100644 --- a/projects/ArchR/packages/emulators/standalone/drastic-sa/sources/libdrastouch.c +++ b/projects/ArchR/packages/emulators/standalone/drastic-sa/sources/libdrastouch.c @@ -6,6 +6,79 @@ #include #include +// --- Minimal GLES2 types and constants (no libGLESv2 header dependency) --- +typedef unsigned int GLenum; +typedef unsigned int GLuint; +typedef int GLint; +typedef int GLsizei; +typedef unsigned char GLboolean; +typedef float GLfloat; +typedef char GLchar; +typedef void GLvoid; + +#define GL_FALSE 0 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_VIEWPORT 0x0BA2 +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_FLOAT 0x1406 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_BLEND 0x0BE2 +#define GL_SCISSOR_TEST 0x0C11 + +// --- GLES2 function pointers resolved at runtime --- +static GLuint (*p_glCreateShader)(GLenum) = NULL; +static void (*p_glShaderSource)(GLuint, GLsizei, const GLchar *const *, const GLint *) = NULL; +static void (*p_glCompileShader)(GLuint) = NULL; +static void (*p_glGetShaderiv)(GLuint, GLenum, GLint *) = NULL; +static void (*p_glDeleteShader)(GLuint) = NULL; +static GLuint (*p_glCreateProgram)(void) = NULL; +static void (*p_glAttachShader)(GLuint, GLuint) = NULL; +static void (*p_glBindAttribLocation)(GLuint, GLuint, const GLchar *) = NULL; +static void (*p_glLinkProgram)(GLuint) = NULL; +static void (*p_glGetProgramiv)(GLuint, GLenum, GLint *) = NULL; +static void (*p_glDeleteProgram)(GLuint) = NULL; +static GLint (*p_glGetUniformLocation)(GLuint, const GLchar *) = NULL; +static void (*p_glUniform1i)(GLint, GLint) = NULL; +static void (*p_glUniform2f)(GLint, GLfloat, GLfloat) = NULL; +static void (*p_glTexParameteri)(GLenum, GLenum, GLint) = NULL; +static void (*p_glGetIntegerv)(GLenum, GLint *) = NULL; +static void (*p_glViewport)(GLint, GLint, GLsizei, GLsizei) = NULL; +static void (*p_glUseProgram)(GLuint) = NULL; +static void (*p_glBindBuffer)(GLenum, GLuint) = NULL; +static void (*p_glEnableVertexAttribArray)(GLuint) = NULL; +static void (*p_glDisableVertexAttribArray)(GLuint) = NULL; +static void (*p_glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *) = NULL; +static void (*p_glDrawArrays)(GLenum, GLint, GLsizei) = NULL; +static void (*p_glEnable)(GLenum) = NULL; +static void (*p_glDisable)(GLenum) = NULL; + +// --- Shader state --- +#define SHADER_NONE 0 // No shader; use GL's built-in bilinear filtering (default) +#define SHADER_SHARP_BILINEAR 1 +#define SHADER_SHARP_SHIMMERLESS 2 +#define SHADER_QUILEZ 3 +#define SHADER_SCANLINES 4 +#define SHADER_LCD3X 5 + +static int shader_mode = SHADER_NONE; +static int gl_renderer_desktop = 0; // 1 when SDL uses "opengl" renderer (not "opengles2") +static GLuint shader_program = 0; +static GLint loc_texture = -1; +static GLint loc_texture_size = -1; +static GLint loc_output_size = -1; // sharp-bilinear only +static int shader_frame_calls = 0; + +// --- DS / window state (declared before all functions that use them) --- static int ds_screen_width = 256; static int ds_screen_height = 192; static int last_x = -1; @@ -29,6 +102,8 @@ static SDL_Texture* screens[4]; static SDL_Texture* stylus_tex[2]; static SDL_Rect touch_rect_storage = {0}; static SDL_Rect* touch_rect = NULL; + +// --- SDL2 real function pointers --- static SDL_Renderer* renderer = NULL; static SDL_Window* (*real_SDL_CreateWindow)(const char*, int, int, int, int, Uint32) = NULL; static void (*real_SDL_SetWindowSize)(SDL_Window* window, int w, int h) = NULL; @@ -45,8 +120,396 @@ static void (*real_SDL_PauseAudioDevice)(SDL_AudioDeviceID, int) = NULL; static void (*real_SDL_CloseAudioDevice)(SDL_AudioDeviceID) = NULL; static int (*real_SDL_GetNumAudioDevices)(int) = NULL; static const char* (*real_SDL_GetAudioDeviceName)(int, int) = NULL; +static void (*real_SDL_RenderPresent)(SDL_Renderer*) = NULL; -SDL_Window* SDL_CreateWindow(const char* title, int x, int y, int w, int h, Uint32 flags) { +// --------------------------------------------------------------------------- +// GLES2 runtime loader +// --------------------------------------------------------------------------- + +static void init_gl_funcs(void) { + // SDL_GL_GetProcAddress resolves against the GL context SDL is actually using. + // This works on both libmali (GLES2) and Mesa/panfrost regardless of whether + // SDL picked the GLES2 or OpenGL renderer, unlike dlsym on libGLESv2.so.2 + // which can return stubs that dispatch to the wrong EGL API on Mesa. +#define GLSYM(name) p_##name = (void *)SDL_GL_GetProcAddress(#name) + GLSYM(glCreateShader); + GLSYM(glShaderSource); + GLSYM(glCompileShader); + GLSYM(glGetShaderiv); + GLSYM(glDeleteShader); + GLSYM(glCreateProgram); + GLSYM(glAttachShader); + GLSYM(glBindAttribLocation); + GLSYM(glLinkProgram); + GLSYM(glGetProgramiv); + GLSYM(glDeleteProgram); + GLSYM(glGetUniformLocation); + GLSYM(glUniform1i); + GLSYM(glUniform2f); + GLSYM(glTexParameteri); + GLSYM(glGetIntegerv); + GLSYM(glViewport); + GLSYM(glUseProgram); + GLSYM(glBindBuffer); + GLSYM(glEnableVertexAttribArray); + GLSYM(glDisableVertexAttribArray); + GLSYM(glVertexAttribPointer); + GLSYM(glDrawArrays); + GLSYM(glEnable); + GLSYM(glDisable); +#undef GLSYM + if (!p_glCreateShader) { + // SDL_GL_GetProcAddress failed (no GL context yet, or software renderer). + // Fall back to RTLD_DEFAULT to catch any GLES2 symbols already in process. +#define GLSYM(name) if (!p_##name) p_##name = (void *)dlsym(RTLD_DEFAULT, #name) + GLSYM(glCreateShader); + GLSYM(glShaderSource); + GLSYM(glCompileShader); + GLSYM(glGetShaderiv); + GLSYM(glDeleteShader); + GLSYM(glCreateProgram); + GLSYM(glAttachShader); + GLSYM(glBindAttribLocation); + GLSYM(glLinkProgram); + GLSYM(glGetProgramiv); + GLSYM(glDeleteProgram); + GLSYM(glGetUniformLocation); + GLSYM(glUniform1i); + GLSYM(glUniform2f); + GLSYM(glTexParameteri); + GLSYM(glGetIntegerv); + GLSYM(glViewport); + GLSYM(glUseProgram); + GLSYM(glBindBuffer); + GLSYM(glEnableVertexAttribArray); + GLSYM(glDisableVertexAttribArray); + GLSYM(glVertexAttribPointer); + GLSYM(glDrawArrays); + GLSYM(glEnable); + GLSYM(glDisable); +#undef GLSYM + } +} + +// --------------------------------------------------------------------------- +// Shader GLSL sources +// --------------------------------------------------------------------------- + +// Vertex shader shared by both filter shaders +static const char *VERT_SRC = + "attribute vec2 a_position;\n" + "attribute vec2 a_texcoord;\n" + "varying vec2 v_texcoord;\n" + "void main() {\n" + " gl_Position = vec4(a_position, 0.0, 1.0);\n" + " v_texcoord = a_texcoord;\n" + "}\n"; + +// Themaister sharp-bilinear with minimum prescale of 2. +// Minimum of 2 ensures correct behaviour with Hi-Res 3D (512×384→640×480) +// where floor(scale)=1 would otherwise fall back to pure bilinear. +static const char *FRAG_SHARP_BILINEAR = + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform sampler2D u_texture;\n" + "uniform vec2 u_texture_size;\n" + "uniform vec2 u_output_size;\n" + "void main() {\n" + " vec2 scale = max(vec2(2.0), floor(u_output_size / u_texture_size));\n" + " vec2 texel = v_texcoord * u_texture_size;\n" + " vec2 texel_floored = floor(texel);\n" + " vec2 s = fract(texel);\n" + " vec2 region_range = 0.5 - 0.5 / scale;\n" + " vec2 center_dist = s - 0.5;\n" + " vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5;\n" + " vec2 mod_texel = texel_floored + f;\n" + " gl_FragColor = SWIZ(texture2D(u_texture, mod_texel / u_texture_size));\n" + "}\n"; + +// Scanlines: sharp-bilinear-2x base with every other output row darkened +static const char *FRAG_SCANLINES = + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform sampler2D u_texture;\n" + "uniform vec2 u_texture_size;\n" + "uniform vec2 u_output_size;\n" + "void main() {\n" + " vec2 scale = max(vec2(2.0), floor(u_output_size / u_texture_size));\n" + " vec2 texel = v_texcoord * u_texture_size;\n" + " vec2 texel_floored = floor(texel);\n" + " vec2 s = fract(texel);\n" + " vec2 region_range = 0.5 - 0.5 / scale;\n" + " vec2 center_dist = s - 0.5;\n" + " vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5;\n" + " vec2 mod_texel = texel_floored + f;\n" + " vec4 color = SWIZ(texture2D(u_texture, mod_texel / u_texture_size));\n" + " float scan = mod(floor(gl_FragCoord.y), 2.0);\n" + " color.rgb *= mix(1.0, 0.65, scan);\n" + " gl_FragColor = color;\n" + "}\n"; + +// LCD3x: sharp-bilinear-2x base with RGB subpixel columns and pixel gap rows. +// Simulates the NDS LCD panel's visible subpixel structure. +// Branchless mask selection via step/mix; *2.0+clamp compensates for the ~50% +// average brightness loss the subpixel mask would otherwise cause. +static const char *FRAG_LCD3X = + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform sampler2D u_texture;\n" + "uniform vec2 u_texture_size;\n" + "uniform vec2 u_output_size;\n" + "void main() {\n" + " vec2 scale = max(vec2(2.0), floor(u_output_size / u_texture_size));\n" + " vec2 texel = v_texcoord * u_texture_size;\n" + " vec2 texel_floored = floor(texel);\n" + " vec2 s = fract(texel);\n" + " vec2 region_range = 0.5 - 0.5 / scale;\n" + " vec2 center_dist = s - 0.5;\n" + " vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5;\n" + " vec2 mod_texel = texel_floored + f;\n" + " vec4 color = SWIZ(texture2D(u_texture, mod_texel / u_texture_size));\n" + " float px = mod(floor(gl_FragCoord.x), 3.0);\n" + " vec3 col_r = vec3(1.0, 0.25, 0.25);\n" + " vec3 col_g = vec3(0.25, 1.0, 0.25);\n" + " vec3 col_b = vec3(0.25, 0.25, 1.0);\n" + " vec3 mask = mix(col_r, col_g, step(1.0, px));\n" + " mask = mix(mask, col_b, step(2.0, px));\n" + " float py = mod(floor(gl_FragCoord.y), 3.0);\n" + " mask *= mix(0.5, 1.0, step(1.0, py));\n" + " color.rgb = min(color.rgb * mask * 2.0, vec3(1.0));\n" + " gl_FragColor = color;\n" + "}\n"; + +// Sharp-shimmerless: nearest-neighbor within source texels; boundary-crossing output +// pixels sample a fixed sub-texel position so blend ratios don't drift with sub-pixel +// scroll, eliminating shimmer. +static const char *FRAG_SHARP_SHIMMERLESS = + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform sampler2D u_texture;\n" + "uniform vec2 u_texture_size;\n" + "uniform vec2 u_output_size;\n" + "void main() {\n" + " vec2 pixel = v_texcoord * u_output_size;\n" + " vec2 scale = u_output_size / u_texture_size;\n" + " vec2 invscale = u_texture_size / u_output_size;\n" + " vec2 pixel_tl = floor(pixel);\n" + " vec2 pixel_br = floor(pixel + vec2(1.0));\n" + " vec2 texel_tl = floor(invscale * pixel_tl);\n" + " vec2 texel_br = floor(invscale * pixel_br);\n" + " vec2 mod_texel = texel_br + vec2(0.5);\n" + " mod_texel -=\n" + " (vec2(1.0) - step(texel_br, texel_tl))\n" + " * (scale * texel_br - pixel_tl);\n" + " gl_FragColor = SWIZ(texture2D(u_texture, mod_texel / u_texture_size));\n" + "}\n"; + +// Inigo Quilez smooth Hermite interpolation (smootherstep) +static const char *FRAG_QUILEZ = + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform sampler2D u_texture;\n" + "uniform vec2 u_texture_size;\n" + "void main() {\n" + " vec2 p = v_texcoord * u_texture_size + vec2(0.5);\n" + " vec2 i = floor(p);\n" + " vec2 f = p - i;\n" + " f = f * f * f * (f * (f * 6.0 - vec2(15.0)) + vec2(10.0));\n" + " p = i + f;\n" + " p = (p - vec2(0.5)) / u_texture_size;\n" + " gl_FragColor = SWIZ(texture2D(u_texture, p));\n" + "}\n"; + +// --------------------------------------------------------------------------- +// Shader program helpers +// --------------------------------------------------------------------------- + +static GLuint make_gl_shader(GLenum type, const char *preamble, const char *src) { + if (!p_glCreateShader) return 0; + GLuint s = p_glCreateShader(type); + if (!s) return 0; + const GLchar *srcs[] = { preamble, src }; + p_glShaderSource(s, 2, (const GLchar *const *)srcs, NULL); + p_glCompileShader(s); + GLint ok = GL_FALSE; + p_glGetShaderiv(s, GL_COMPILE_STATUS, &ok); + if (!ok) { p_glDeleteShader(s); return 0; } + return s; +} + +static GLuint make_gl_program(const char *vert_src, const char *frag_src) { + // GLSL ES 1.00 (GLES2) shaders need two tweaks to compile under desktop OpenGL: + // - Prepend "#version 120" so attribute/varying/texture2D are available + // - Drop "precision mediump float;" which is GLES2-only and invalid in desktop GLSL + static const char FRAG_ES_PREFIX[] = "precision mediump float;\n"; + // SDL's desktop OpenGL renderer stores textures as GL_RGBA → no swizzle needed. + // SDL's GLES2 renderer (both libmali and Mesa/Panfrost) uses GL_BGRA_EXT when the + // GL_EXT_texture_format_BGRA8888 extension is available, so .bgra corrects channels. + const char *vpreamble = gl_renderer_desktop + ? "#version 120\n#define SWIZ(c) (c)\n" + : "#define SWIZ(c) (c).bgra\n"; + const char *fpreamble = gl_renderer_desktop + ? "#version 120\n#define SWIZ(c) (c)\n" + : "#define SWIZ(c) (c).bgra\n"; + const char *fbody = frag_src; + if (gl_renderer_desktop && + strncmp(frag_src, FRAG_ES_PREFIX, sizeof(FRAG_ES_PREFIX) - 1) == 0) + fbody = frag_src + sizeof(FRAG_ES_PREFIX) - 1; + + GLuint vert = make_gl_shader(GL_VERTEX_SHADER, vpreamble, vert_src); + if (!vert) return 0; + GLuint frag = make_gl_shader(GL_FRAGMENT_SHADER, fpreamble, fbody); + if (!frag) { p_glDeleteShader(vert); return 0; } + GLuint prog = p_glCreateProgram(); + if (!prog) { p_glDeleteShader(vert); p_glDeleteShader(frag); return 0; } + p_glAttachShader(prog, vert); + p_glAttachShader(prog, frag); + // Pin attribute locations before linking so we can use constants + p_glBindAttribLocation(prog, 0, "a_position"); + p_glBindAttribLocation(prog, 1, "a_texcoord"); + p_glLinkProgram(prog); + p_glDeleteShader(vert); + p_glDeleteShader(frag); + GLint ok = GL_FALSE; + p_glGetProgramiv(prog, GL_LINK_STATUS, &ok); + if (!ok) { p_glDeleteProgram(prog); return 0; } + return prog; +} + +// Called from SDL_CreateRenderer once the GLES2 context is live +static void init_shader_program(void) { + if (shader_mode == SHADER_NONE) return; + init_gl_funcs(); + fprintf(stderr, "[drastouch] init_shader: mode=%d glCreateShader=%s\n", + shader_mode, p_glCreateShader ? "ok" : "NULL"); + if (!p_glCreateShader) { shader_mode = SHADER_NONE; return; } + const char *frag; + switch (shader_mode) { + case SHADER_SHARP_SHIMMERLESS: frag = FRAG_SHARP_SHIMMERLESS; break; + case SHADER_QUILEZ: frag = FRAG_QUILEZ; break; + case SHADER_SCANLINES: frag = FRAG_SCANLINES; break; + case SHADER_LCD3X: frag = FRAG_LCD3X; break; + default: frag = FRAG_SHARP_BILINEAR; break; + } + shader_program = make_gl_program(VERT_SRC, frag); + fprintf(stderr, "[drastouch] shader_program=%u\n", shader_program); + if (!shader_program) { shader_mode = SHADER_NONE; return; } + loc_texture = p_glGetUniformLocation(shader_program, "u_texture"); + loc_texture_size = p_glGetUniformLocation(shader_program, "u_texture_size"); + loc_output_size = p_glGetUniformLocation(shader_program, "u_output_size"); +} + +// --------------------------------------------------------------------------- +// Per-frame shader render pass +// --------------------------------------------------------------------------- + +// Replace SDL_RenderCopy for a single DS screen texture with a GLES2 shader pass +static int run_shader_copy(SDL_Renderer *r, SDL_Texture *texture, + const SDL_Rect *srcrect, const SDL_Rect *dstrect) { + // Actual source texture dimensions + int tex_w = 0, tex_h = 0; + SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h); + if (tex_w == 0 || tex_h == 0) goto fallback; + + // Flush SDL's batched commands before issuing raw GL + SDL_RenderFlush(r); + + // Convert dstrect from logical SDL coords to physical GL pixels + int out_w, out_h; + SDL_GetRendererOutputSize(r, &out_w, &out_h); + float sx = (logical_width > 0) ? (float)out_w / logical_width : 1.0f; + float sy = (logical_height > 0) ? (float)out_h / logical_height : 1.0f; + int gl_w = (int)(dstrect->w * sx); + int gl_h = (int)(dstrect->h * sy); + // GL origin is bottom-left; SDL origin is top-left + int gl_x = (int)(dstrect->x * sx); + int gl_y = out_h - (int)(dstrect->y * sy) - gl_h; + + if (gl_w < 32 || gl_h < 32) goto fallback; + + // Bind source texture to GL_TEXTURE_2D via SDL + GLfloat texw = 1.0f, texh = 1.0f; + if (SDL_GL_BindTexture(texture, &texw, &texh) != 0) { + static int bind_fail_logged = 0; + if (!bind_fail_logged) { + fprintf(stderr, "[drastouch] SDL_GL_BindTexture failed: %s\n", SDL_GetError()); + bind_fail_logged = 1; + } + goto fallback; + } + + // Save GL state we will modify + GLint saved_viewport[4], saved_program, saved_abuf, saved_blend, saved_scissor; + p_glGetIntegerv(GL_VIEWPORT, saved_viewport); + p_glGetIntegerv(GL_CURRENT_PROGRAM, &saved_program); + p_glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &saved_abuf); + p_glGetIntegerv(GL_BLEND, &saved_blend); + p_glGetIntegerv(GL_SCISSOR_TEST, &saved_scissor); + // Our draw is always fully opaque; disable blending and clipping + p_glDisable(GL_BLEND); + p_glDisable(GL_SCISSOR_TEST); + + p_glViewport(gl_x, gl_y, gl_w, gl_h); + p_glUseProgram(shader_program); + if (loc_texture >= 0) p_glUniform1i(loc_texture, 0); + if (loc_texture_size >= 0) + p_glUniform2f(loc_texture_size, (float)tex_w, (float)tex_h); + if (loc_output_size >= 0) + p_glUniform2f(loc_output_size, (float)gl_w, (float)gl_h); + + // UV sub-rectangle within the source texture + float u0 = 0.0f, v0 = 0.0f, u1 = texw, v1 = texh; + if (srcrect) { + u0 = (float)srcrect->x / tex_w * texw; + v0 = (float)srcrect->y / tex_h * texh; + u1 = (float)(srcrect->x + srcrect->w) / tex_w * texw; + v1 = (float)(srcrect->y + srcrect->h) / tex_h * texh; + } + + // SDL2/GLES2 stores textures with row-0 at the top in memory; GL has V=0 at bottom. + // We flip V so the image appears right-way-up after the GL y-flipped viewport. + // pos(x,y) | uv(u,v) + GLfloat verts[] = { + -1.0f, -1.0f, u0, v1, // bottom-left -> texture bottom-left + 1.0f, -1.0f, u1, v1, // bottom-right -> texture bottom-right + -1.0f, 1.0f, u0, v0, // top-left -> texture top-left + 1.0f, 1.0f, u1, v0, // top-right -> texture top-right + }; + + p_glBindBuffer(GL_ARRAY_BUFFER, 0); + p_glEnableVertexAttribArray(0); + p_glEnableVertexAttribArray(1); + p_glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), verts); + p_glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), verts + 2); + p_glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + // SDL2's GLES2 renderer caches whether attrib arrays 0/1 are enabled and skips + // re-enabling them when it thinks they're already on. Leaving them enabled here + // keeps that cache consistent on libmali (opengles2 renderer). + // SDL2's desktop OpenGL renderer does NOT cache this state — leaving attribs + // enabled with stale stack pointers corrupts its subsequent rendering (black menu). + if (gl_renderer_desktop) { + p_glDisableVertexAttribArray(0); + p_glDisableVertexAttribArray(1); + } + + SDL_GL_UnbindTexture(texture); + + p_glUseProgram(saved_program); + p_glViewport(saved_viewport[0], saved_viewport[1], saved_viewport[2], saved_viewport[3]); + p_glBindBuffer(GL_ARRAY_BUFFER, saved_abuf); + if (saved_blend) p_glEnable(GL_BLEND); else p_glDisable(GL_BLEND); + if (saved_scissor) p_glEnable(GL_SCISSOR_TEST); else p_glDisable(GL_SCISSOR_TEST); + return 0; + +fallback: + return real_SDL_RenderCopy(r, texture, srcrect, dstrect); +} + +// --------------------------------------------------------------------------- +// SDL2 hooks +// --------------------------------------------------------------------------- + +SDL_Window* SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) { int num_displays = SDL_GetNumVideoDisplays(); int total_width = 0; int total_height = 0; @@ -110,38 +573,51 @@ void SDL_SetWindowSize(SDL_Window* window, int w, int h) { SDL_Renderer* SDL_CreateRenderer(SDL_Window* window, int index, Uint32 flags) { renderer = real_SDL_CreateRenderer(window, index, flags); - // Just in case it's already set - SDL_RenderGetLogicalSize(renderer, &logical_width, &logical_height); + if (renderer) { + // Just in case it's already set + SDL_RenderGetLogicalSize(renderer, &logical_width, &logical_height); + SDL_RendererInfo info; + if (SDL_GetRendererInfo(renderer, &info) == 0) { + fprintf(stderr, "[drastouch] SDL renderer: %s (flags=0x%x)\n", info.name, info.flags); + gl_renderer_desktop = (strcmp(info.name, "opengl") == 0); + } + init_shader_program(); // GLES2 context is live at this point + } return renderer; } int SDL_RenderSetLogicalSize(SDL_Renderer* renderer, int w, int h) { int result = real_SDL_RenderSetLogicalSize(renderer, w, h); - // Otherwise store it here + // Also store it here so run_shader_copy can convert logical→physical coords logical_width = w; logical_height = h; return result; } +void SDL_RenderPresent(SDL_Renderer *r) { + shader_frame_calls = 0; + real_SDL_RenderPresent(r); +} + SDL_Texture* SDL_CreateTexture(SDL_Renderer *renderer, Uint32 format, int type, int w, int h) { - SDL_Texture* texture = real_SDL_CreateTexture(renderer, format, type, w, h); - // Identify DS screen and stylus textures - if (type == SDL_TEXTUREACCESS_STREAMING) { - if (w == 512 && h == 384) { + SDL_Texture* texture = real_SDL_CreateTexture(renderer, format, type, w, h); + // Identify DS screen and stylus textures + if (type == SDL_TEXTUREACCESS_STREAMING) { + if (w == 512 && h == 384) { ds_screen_width = 512; ds_screen_height = 384; - if (!screens[0]) screens[0] = texture; - else if (!screens[1]) screens[1] = texture; + if (!screens[0]) screens[0] = texture; + else if (!screens[1]) screens[1] = texture; } else if (w == 256 && h == 192 && !screens[0]) { - if (!screens[2]) screens[2] = texture; - else if (!screens[3]) screens[3] = texture; + if (!screens[2]) screens[2] = texture; + else if (!screens[3]) screens[3] = texture; } } if (w == 32 && h == 32) { - if (!stylus_tex[0]) stylus_tex[0] = texture; - else if (!stylus_tex[1]) stylus_tex[1] = texture; + if (!stylus_tex[0]) stylus_tex[0] = texture; + else if (!stylus_tex[1]) stylus_tex[1] = texture; } - return texture; + return texture; } int SDL_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_Rect *dstrect) { @@ -171,7 +647,21 @@ int SDL_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect // Make stylus fully transparent for actual touchscreens if (actual_touch && (texture == stylus_tex[0] || texture == stylus_tex[1])) SDL_SetTextureAlphaMod(texture, 0); - + + // Apply pixel shader to DS screen textures when one is configured. + // Cap at 2 shader passes per frame so menu overlays (drawn after the two NDS + // screens) fall through to normal SDL rendering without breaking blending. + // Skip when rendering into a texture target — viewport math uses screen size. + if (shader_program && dstrect && shader_frame_calls < 2 && + SDL_GetRenderTarget(renderer) == NULL) { + for (int i = 0; i < 4; i++) { + if (screens[i] && texture == screens[i]) { + shader_frame_calls++; + return run_shader_copy(renderer, texture, srcrect, dstrect); + } + } + } + return real_SDL_RenderCopy(renderer, texture, srcrect, dstrect); } @@ -233,6 +723,8 @@ int SDL_PollEvent(SDL_Event* event) { if (!actual_touch) actual_touch = 1; + if (!touch_rect) return 0; + int x = (int)(event->tfinger.x * phys_width); int y = (int)(event->tfinger.y * phys_height); if (xy_idx == 1) @@ -269,6 +761,8 @@ int SDL_PollEvent(SDL_Event* event) { break; } case SDL_FINGERMOTION: { + if (!touch_rect) return 0; + int x = (int)(event->tfinger.x * phys_width); int y = (int)(event->tfinger.y * phys_height); if (xy_idx == 1) @@ -327,6 +821,21 @@ static void init(void) { real_SDL_CloseAudioDevice = dlsym(RTLD_NEXT, "SDL_CloseAudioDevice"); real_SDL_GetNumAudioDevices = dlsym(RTLD_NEXT, "SDL_GetNumAudioDevices"); real_SDL_GetAudioDeviceName = dlsym(RTLD_NEXT, "SDL_GetAudioDeviceName"); + real_SDL_RenderPresent = dlsym(RTLD_NEXT, "SDL_RenderPresent"); + + const char *shader_str = getenv("DSHOOK_SHADER"); + if (shader_str) { + if (strcmp(shader_str, "sharp-bilinear") == 0) + shader_mode = SHADER_SHARP_BILINEAR; + else if (strcmp(shader_str, "quilez") == 0) + shader_mode = SHADER_QUILEZ; + else if (strcmp(shader_str, "scanlines") == 0) + shader_mode = SHADER_SCANLINES; + else if (strcmp(shader_str, "lcd3x") == 0) + shader_mode = SHADER_LCD3X; + else if (strcmp(shader_str, "sharp-shimmerless") == 0) + shader_mode = SHADER_SHARP_SHIMMERLESS; + } const char* threshold_str = getenv("DSHOOK_MIC_THRESH"); if (threshold_str) { @@ -373,6 +882,10 @@ static void cleanup(void) { if (mic_device > 0 && real_SDL_CloseAudioDevice) { real_SDL_CloseAudioDevice(mic_device); } + if (shader_program && p_glDeleteProgram) { + p_glDeleteProgram(shader_program); + shader_program = 0; + } } // Major thanks/credit to Shaun Inman for providing the basis of this hook library! \ No newline at end of file diff --git a/projects/ArchR/packages/emulators/standalone/hypseus-singe/sources/start_hypseus.sh b/projects/ArchR/packages/emulators/standalone/hypseus-singe/sources/start_hypseus.sh index df3fb8e1f9..764c1c6576 100755 --- a/projects/ArchR/packages/emulators/standalone/hypseus-singe/sources/start_hypseus.sh +++ b/projects/ArchR/packages/emulators/standalone/hypseus-singe/sources/start_hypseus.sh @@ -4,6 +4,9 @@ # Copyright (C) 2021-present Shanti Gilbert (https://github.com/shantigilbert) # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) +. /etc/profile +set_kill set "-9 hypseus" + dir="${1}" name=${dir##*/} name=${name%.*} @@ -11,53 +14,49 @@ config="/storage/.config/game/configs/hypseus" configfile="${config}/hypinput.ini" # Attempt to auto configure gamepad -# GAMEPADINFO="$(sdljoytest -skip_loop)" -#JOYGUID=$(echo "${GAMEPADINFO}" | grep "Joystick 0 Guid " | sed "s|Joystick 0 Guid ||") JOYNAME=$(echo "${GAMEPADINFO}" | grep "Joystick 0 name " | sed "s|Joystick 0 name ||" | sed "s|'||g") -# -for file in /usr/share/libretro/autoconfig/*.cfg; do - GAMEPAD=$(cat "$file" | grep input_device | cut -d'"' -f 2) - if [ "${JOYNAME}" == "${GAMEPAD}" ]; then - GPFILE="${file}" +GPFILE="/usr/share/libretro/autoconfig/${JOYNAME}.cfg" + +if [[ -f "${GPFILE}" ]]; then # Other keys to consider KEY_SCREENSHOT KEY_QUIT KEY_PAUSE for key in KEY_UP KEY_DOWN KEY_LEFT KEY_RIGHT KEY_BUTTON1 KEY_BUTTON2 KEY_BUTTON3 KEY_START1 KEY_COIN1; do case ${key} in "KEY_UP") - button=$(cat "${GPFILE}" | grep -E 'input_up_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_up_btn\b' | cut -d '"' -f2) keyboard="1073741906 0" ;; "KEY_DOWN") - button=$(cat "${GPFILE}" | grep -E 'input_down_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_down_btn\b' | cut -d '"' -f2) keyboard="1073741905 0" ;; "KEY_LEFT") - button=$(cat "${GPFILE}" | grep -E 'input_left_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_left_btn\b' | cut -d '"' -f2) keyboard="1073741904 0" ;; "KEY_RIGHT") - button=$(cat "${GPFILE}" | grep -E 'input_right_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_right_btn\b' | cut -d '"' -f2) keyboard="1073741903 0" ;; "KEY_BUTTON1") - button=$(cat "${GPFILE}" | grep -E 'input_a_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_a_btn\b' | cut -d '"' -f2) keyboard="1073742048 0" ;; "KEY_BUTTON2") - button=$(cat "${GPFILE}" | grep -E 'input_b_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_b_btn\b' | cut -d '"' -f2) keyboard="1073742050 0" ;; "KEY_BUTTON3") - button=$(cat "${GPFILE}" | grep -E 'input_x_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_x_btn\b' | cut -d '"' -f2) keyboard="32 0" ;; "KEY_START1") - button=$(cat "${GPFILE}" | grep -E 'input_start_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_start_btn\b' | cut -d '"' -f2) keyboard="49 0" ;; "KEY_COIN1") - button=$(cat "${GPFILE}" | grep -E 'input_select_btn' | cut -d '"' -f2) + button=$(cat "${GPFILE}" | grep -E '^input_select_btn\b' | cut -d '"' -f2) keyboard="53 54" ;; esac @@ -71,8 +70,7 @@ for file in /usr/share/libretro/autoconfig/*.cfg; do sed -i "s|${key}.*|${key} = ${keyboard} ${button} |" ${configfile} done - fi -done # finish auto gamepad +fi # finish auto gamepad if [[ -f "${dir}/${name}.commands" ]]; then params=$(<"${dir}/${name}.commands") diff --git a/projects/ArchR/packages/emulators/standalone/ppsspp-sa/patches/005-hide-unsupported-ui-items.patch b/projects/ArchR/packages/emulators/standalone/ppsspp-sa/patches/005-hide-unsupported-ui-items.patch new file mode 100644 index 0000000000..2eb9bf1708 --- /dev/null +++ b/projects/ArchR/packages/emulators/standalone/ppsspp-sa/patches/005-hide-unsupported-ui-items.patch @@ -0,0 +1,87 @@ +diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp +index 1af913cbc8..fd5c7fccaf 100644 +--- a/UI/MainScreen.cpp ++++ b/UI/MainScreen.cpp +@@ -285,19 +285,19 @@ void MainScreen::CreateMainButtons(UI::ViewGroup *parent, bool portrait) { + parent->Add(portrait ? new Choice(ImageID("I_GEAR"), portrait ? new LinearLayoutParams() : nullptr) : new Choice(mm->T("Game Settings", "Settings")))->OnClick.Handle(this, &MainScreen::OnGameSettings); + parent->Add(portrait ? new Choice(ImageID("I_INFO"), portrait ? new LinearLayoutParams() : nullptr) : new Choice(mm->T("About PPSSPP")))->OnClick.Handle(this, &MainScreen::OnCredits); + +- if (!portrait) { +- parent->Add(new Choice(mm->T("www.ppsspp.org")))->OnClick.Handle(this, &MainScreen::OnPPSSPPOrg); +- } +- +- if (!System_GetPropertyBool(SYSPROP_APP_GOLD) && (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_VR)) { +- Choice *gold = parent->Add(portrait ? new Choice(ImageID("I_ICON_GOLD"), portrait ? new LinearLayoutParams() : nullptr) : new Choice(mm->T("Buy PPSSPP Gold"))); +- gold->OnClick.Add([this](UI::EventParams &) { +- LaunchBuyGold(this->screenManager()); +- }); +- gold->SetIconRight(ImageID("I_ICON_GOLD"), 0.5f); +- gold->SetImageScale(0.6f); // for the left-icon in case of vertical. +- gold->SetShine(true); +- } ++ //if (!portrait) { ++ // parent->Add(new Choice(mm->T("www.ppsspp.org")))->OnClick.Handle(this, &MainScreen::OnPPSSPPOrg); ++ //} ++ ++ //if (!System_GetPropertyBool(SYSPROP_APP_GOLD) && (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_VR)) { ++ // Choice *gold = parent->Add(portrait ? new Choice(ImageID("I_ICON_GOLD"), portrait ? new LinearLayoutParams() : nullptr) : new Choice(mm->T("Buy PPSSPP Gold"))); ++ // gold->OnClick.Add([this](UI::EventParams &) { ++ // LaunchBuyGold(this->screenManager()); ++ // }); ++ // gold->SetIconRight(ImageID("I_ICON_GOLD"), 0.5f); ++ // gold->SetImageScale(0.6f); // for the left-icon in case of vertical. ++ // gold->SetShine(true); ++ //} + + if (!portrait) { + parent->Add(new Spacer(16.0)); +@@ -359,8 +359,9 @@ void MainScreen::CreateViews() { + + Button *focusButton = nullptr; + if (hasStorageAccess) { +- CreateBrowserTab(Path(g_Config.currentDirectory), "Games", "How to get games", getGamesUri, BrowseFlags::STANDARD, &g_Config.bGridView2, &g_Config.fGameListScrollPosition); +- CreateBrowserTab(GetSysDirectory(DIRECTORY_GAME), "Homebrew & Demos", "How to get homebrew & demos", getHomebrewUri, BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, &g_Config.fHomebrewScrollPosition); ++ CreateBrowserTab(Path(g_Config.currentDirectory), "Games", "", "", BrowseFlags::STANDARD, &g_Config.bGridView2, &g_Config.fGameListScrollPosition); ++ CreateBrowserTab(GetSysDirectory(DIRECTORY_GAME), "Homebrew & Demos", "", "", BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, &g_Config.fHomebrewScrollPosition); ++ + + if (g_Config.bRemoteTab && !g_Config.sLastRemoteISOServer.empty()) { + Path remotePath(FormatRemoteISOUrl(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort, RemoteSubdir().c_str())); +diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp +index 7bd09b9fe7..4030ee32bc 100644 +--- a/UI/MiscScreens.cpp ++++ b/UI/MiscScreens.cpp +@@ -547,33 +547,6 @@ void CreditsScreen::CreateDialogViews(UI::ViewGroup *parent) { + } + + int rightYOffset = 0; +- if (!System_GetPropertyBool(SYSPROP_APP_GOLD)) { +- ScreenManager *sm = screenManager(); +- Choice *gold = new Choice(mm->T("Buy PPSSPP Gold")); +- gold->SetIconRight(ImageID("I_ICON_GOLD"), 0.5f); +- gold->SetImageScale(0.6f); // for the left-icon in case of vertical. +- gold->SetShine(true); +- +- left->Add(gold)->OnClick.Add([sm](UI::EventParams) { +- LaunchBuyGold(sm); +- }); +- rightYOffset = 74; +- } +- left->Add(new Choice(cr->T("PPSSPP Forums"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &e) { +- System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://forums.ppsspp.org"); +- }); +- left->Add(new Choice(cr->T("Discord"), ImageID("I_LOGO_DISCORD")))->OnClick.Add([](UI::EventParams &e) { +- System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://discord.gg/5NJB6dD"); +- }); +- left->Add(new Choice("www.ppsspp.org", ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &e) { +- System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org"); +- }); +- right->Add(new Choice(cr->T("Privacy Policy"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &e) { +- System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/privacy"); +- }); +- right->Add(new Choice(cr->T("@PPSSPP_emu"), ImageID("I_LOGO_X")))->OnClick.Add([](UI::EventParams &e) { +- System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://x.com/PPSSPP_emu"); +- }); + + if (System_GetPropertyBool(SYSPROP_SUPPORTS_SHARE_TEXT)) { + right->Add(new Choice(cr->T("Share PPSSPP"), ImageID("I_SHARE")))->OnClick.Add([](UI::EventParams &e) {