Compare commits

...

16 Commits

Author SHA1 Message Date
Logan McNaughton e1ad3aac06 use lockstep mode 2026-07-07 09:43:47 +02:00
PolygonPrincess e8a7abffe3 Add cli flag for widescreen (#1152)
* Add cli flag for widescreen and enable config fallback

* Fix else statement brace spacing and trailing whitespace

* Fix trailing whitespace within args.widescreen else statement
2026-07-06 12:54:51 +00:00
dependabot[bot] f7ad6a4b0d Bump rust-toolchain from 1.96.0 to 1.96.1 (#1151)
Bumps [rust-toolchain](https://github.com/rust-lang/rust) from 1.96.0 to 1.96.1.
- [Release notes](https://github.com/rust-lang/rust/releases)
- [Changelog](https://github.com/rust-lang/rust/blob/main/RELEASES.md)
- [Commits](https://github.com/rust-lang/rust/compare/1.96.0...1.96.1)

---
updated-dependencies:
- dependency-name: rust-toolchain
  dependency-version: 1.96.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 04:34:17 +00:00
Logan McNaughton 1bfb50de8a re-arrange input profiles (#1150) 2026-07-05 10:43:23 +00:00
Logan McNaughton 3bc7c96191 move input polling (#1145)
* move input polling

* more

* more

* more
2026-07-02 08:04:51 +00:00
Logan McNaughton 032bf1acf3 Update contribution guidelines (#1143) 2026-07-01 07:58:17 +00:00
Logan McNaughton 8bc765c1a3 match RA branding softcore->casual (#1142) 2026-07-01 07:34:48 +00:00
Logan McNaughton da061240af normalize no-intro names (#1139) 2026-06-30 10:32:43 +00:00
Logan McNaughton 407a1b967c Re-arrange settings (#1138)
* update setting locations

* tra
2026-06-30 09:53:03 +00:00
999sian ad756cd6bd settings: add a dark/light theme toggle (#1132)
* settings: add dark/light theme toggle

* i18n: translate theme selector strings

* settings: align Resolution and Theme dropdowns in a GridBox
2026-06-30 09:17:12 +00:00
Logan McNaughton 6e11bc18d6 translation tweaks (#1137) 2026-06-30 05:24:48 +00:00
Logan McNaughton c8eee9f727 don't copy from db (#1136) 2026-06-30 05:23:38 +00:00
Logan McNaughton 01a53ce1c0 use no-intro names in netplay/cheats (#1133)
* use no-intro names in netplay/cheats

* more

* more
2026-06-29 19:37:33 +00:00
Logan McNaughton 0eddf31f92 update contributing guidelines (#1130) 2026-06-29 09:53:00 +00:00
Logan McNaughton e257ba717b update ggrs (#1127) 2026-06-27 08:19:14 +00:00
Logan McNaughton 7a797165fd Fix translation for 'Open Saves Folder' in Portuguese (#1125) 2026-06-26 07:23:50 +00:00
34 changed files with 24101 additions and 1259 deletions
Generated
+17 -27
View File
@@ -351,9 +351,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.102"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
[[package]]
name = "arbitrary"
@@ -2618,8 +2618,9 @@ dependencies = [
[[package]]
name = "ggrs"
version = "0.12.0"
source = "git+https://github.com/gschup/ggrs.git#d260417700bef25482ba0861587905f643385e14"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "672a16c1d778ad2d7a6218700ba0863a9e510e9446b08f3644460a9884aed048"
dependencies = [
"bincode 1.3.3",
"bitfield-rle",
@@ -2789,12 +2790,12 @@ dependencies = [
"mimalloc",
"open",
"postcard",
"quick-xml 0.40.1",
"rand 0.10.1",
"regex",
"reqwest",
"rfd",
"rustc-hash 2.1.2",
"sdl3-image-sys",
"sdl3-src",
"sdl3-sys",
"sdl3-ttf-sys",
@@ -5700,6 +5701,15 @@ dependencies = [
"serde",
]
[[package]]
name = "quick-xml"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.46"
@@ -6430,26 +6440,6 @@ dependencies = [
"tiny-skia 0.11.4",
]
[[package]]
name = "sdl3-image-src"
version = "3.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe273101c7dab94551183212eee9adef1a7bf274d407f0b7bfe72482960ab25c"
[[package]]
name = "sdl3-image-sys"
version = "0.6.4+SDL-image-3.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a445f781b39a1c1bc751f5f4612191e0402006e35ad5d02d9193281afad1cf4"
dependencies = [
"cmake",
"pkg-config",
"rpkg-config",
"sdl3-image-src",
"sdl3-sys",
"vcpkg",
]
[[package]]
name = "sdl3-src"
version = "3.4.10"
@@ -8254,7 +8244,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a"
dependencies = [
"proc-macro2",
"quick-xml",
"quick-xml 0.39.4",
"quote",
]
@@ -9434,7 +9424,7 @@ version = "5.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8067892e940ed1727dea64690378601603b31d62dfde019a5335fbb7c0e0ed9"
dependencies = [
"quick-xml",
"quick-xml 0.39.4",
"serde",
"zbus_names",
"zvariant",
+2 -3
View File
@@ -26,7 +26,7 @@ mimalloc = "0.1"
regex = "1.11"
tokio-tungstenite = { version = "0.29", features = ["native-tls-vendored"] }
matchbox_socket = "0.14"
ggrs = { git = "https://github.com/gschup/ggrs.git", features = ["sync-send"] }
ggrs = { version = "0.13", features = ["sync-send"] }
rustc-hash = "2.1"
futures = "0.3"
rand = { version = "0.10", features = ["serde"] }
@@ -36,6 +36,7 @@ postcard = { version = "1.1", features = ["use-std"] }
clap = { version = "4.5", features = ["derive"] }
reqwest = { version = "0.13", default-features = false, features = ["native-tls-vendored", "charset", "http2", "system-proxy", "json", "query"] }
discord-rich-presence = "1.1"
quick-xml = "0.40"
[target.'cfg(not(target_os = "android"))'.dependencies]
slint = { version = "1.16", default-features = false, features = ["compat-1-2", "std", "unstable-winit-030", "backend-winit", "renderer-femtovg-wgpu", "accessibility"], optional = true }
@@ -44,14 +45,12 @@ dirs = "6.0"
open = { version = "5.3", optional = true }
sdl3-sys = { version = "0.6", features = ["build-from-source-static"] }
sdl3-ttf-sys = { version = "0.6", features = ["build-static-vendored", "no-sdlttf-harfbuzz", "no-sdlttf-plutosvg"] }
sdl3-image-sys = { version = "0.6", features = ["build-static-vendored"] }
[target.'cfg(target_os = "android")'.dependencies]
slint = { version = "1.16", default-features = false, features = ["compat-1-2", "std", "backend-android-activity-06", "accessibility"], optional = true }
jni = "0.22"
sdl3-sys = { version = "0.6", features = ["build-from-source"] }
sdl3-ttf-sys = { version = "0.6", features = ["build-from-source", "no-sdlttf-harfbuzz", "no-sdlttf-plutosvg"] }
sdl3-image-sys = { version = "0.6", features = ["build-from-source"] }
[build-dependencies]
winresource = "0.1"
+3 -1
View File
@@ -68,7 +68,9 @@ flatpak run --filesystem=host:ro io.github.gopher64.gopher64 /path/to/rom.z64
## contributing
I am very open to contributions! Please contact me via a GitHub issue or Discord (loganmc10) before doing substantial work on a PR.
PRs that are vibe coded and/or co-authored by AI agents (Plan/Agent mode) are not permitted. If you are going to submit a PR, it should be scoped to a single feature/improvement.
Please contact me via a GitHub issue or Discord (loganmc10) before doing substantial work on a PR.
## license
@@ -24,7 +24,6 @@ class N64Activity : SDLActivity() {
override fun getLibraries(): Array<String> = arrayOf(
"SDL3",
"SDL3_ttf",
"SDL3_image",
"gopher64"
)
+51 -21
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: gopher64\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: 2026-05-11 12:00+0000\n"
"Last-Translator: \n"
"Language-Team: German\n"
@@ -47,37 +47,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr "Spenden (über GitHub)"
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr "Lokales Spiel"
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr "Controller-Konfiguration"
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr "Netplay"
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr "Cheats"
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr "RetroAchievements"
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr "Einstellungen"
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr "Über"
@@ -486,71 +486,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr "Unterstützte Spiele anzeigen"
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr "Einstellungen"
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr "Spiel"
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr "Auflösung:"
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr "SSAA-Herunterskalierung"
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr "Pixelgenaue Skalierung"
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr "Vollbild"
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr "16:9 (gestreckt)"
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr "VSync"
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr "CRT-Shader anwenden"
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr "N64-CPU übertakten (kann Fehler verursachen)"
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr "Expansion Pak deaktivieren"
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr "Rewind aktivieren"
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr "UNFLoader emulieren"
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr "VRU emulieren"
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr "Benutzeroberfläche"
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr "Thema:"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr "System"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr "Dunkel"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr "Hell"
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
+53 -23
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: gopher64\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: 2026-05-11 12:00+0000\n"
"Last-Translator: Gemini\n"
"Language-Team: Spanish (Spain)\n"
@@ -47,37 +47,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr "Donar (a través de GitHub)"
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr "Juego local"
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr "Config. del mando"
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr "Netplay"
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr "Trucos"
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr "RetroAchievements"
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr "Ajustes"
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr "Acerca de"
@@ -399,8 +399,8 @@ msgid ""
msgstr ""
"Configurar un retardo de entrada demasiado bajo hará que el juego se "
"ralentice.\n"
"Puedes reducir el retardo de entrada en el juego pulsando Alt+[ y "
"aumentarlo con Alt+]."
"Puedes reducir el retardo de entrada en el juego pulsando Alt+[ y aumentarlo "
"con Alt+]."
#: src/ui/gui/netplay_wait.slint:101
msgctxt "NetplayWait"
@@ -487,71 +487,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr "Ver juegos compatibles"
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr "Ajustes"
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr "Juego"
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr "Resolución:"
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr "Reducción de escala SSAA"
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr "Escalado por enteros"
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr "Pantalla completa"
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr "Pantalla ancha (estirado)"
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr "Sincronización vertical (VSync)"
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr "Aplicar sombreador CRT"
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr "Overclock CPU N64 (puede causar errores)"
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr "Desactivar Expansion Pak"
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr "Activar rebobinado"
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr "Emular UNFLoader"
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr "Emular VRU"
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr "Interfaz"
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr "Tema:"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr "Sistema"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr "Oscuro"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr "Claro"
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
+53 -23
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: gopher64\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: 2026-05-11 12:00+0000\n"
"Last-Translator: \n"
"Language-Team: French (France)\n"
@@ -47,37 +47,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr "Faire un don (via GitHub)"
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr "Jeu local"
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr "Configuration manette"
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr "Netplay"
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr "Triche"
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr "RetroAchievements"
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr "Paramètres"
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr "À propos"
@@ -399,8 +399,8 @@ msgid ""
"Alt+]."
msgstr ""
"Régler le délai d'entrée trop bas provoquera des ralentissements.\n"
"Vous pouvez diminuer le délai d'entrée en jeu avec Alt+[ et l'augmenter "
"avec Alt+]."
"Vous pouvez diminuer le délai d'entrée en jeu avec Alt+[ et l'augmenter avec "
"Alt+]."
#: src/ui/gui/netplay_wait.slint:101
msgctxt "NetplayWait"
@@ -487,71 +487,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr "Voir les jeux pris en charge"
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr "Paramètres"
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr "Jeu"
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr "Résolution :"
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr "Réduction SSAA"
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr "Mise à l'échelle par entiers"
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr "Plein écran"
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr "Écran large (étiré)"
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr "Synchro verticale"
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr "Appliquer le filtre CRT"
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr "Surcharger le CPU N64 (risque de bugs)"
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr "Désactiver l'Expansion Pak"
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr "Activer le rembobinage"
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr "Émuler UNFLoader"
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr "Émuler le VRU"
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr "Interface"
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr "Thème :"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr "Système"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr "Sombre"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr "Clair"
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
+51 -21
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -47,37 +47,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr ""
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr ""
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr ""
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr ""
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr ""
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr ""
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr ""
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr ""
@@ -480,71 +480,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr ""
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr ""
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr ""
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr ""
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr ""
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr ""
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr ""
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr ""
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr ""
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr ""
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr ""
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr ""
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr ""
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr ""
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr ""
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr ""
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr ""
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr ""
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr ""
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr ""
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
+51 -21
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: gopher64\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: 2026-05-11 12:00+0000\n"
"Last-Translator: \n"
"Language-Team: Japanese\n"
@@ -47,37 +47,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr "GitHubで寄付"
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr "ローカルゲーム"
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr "コントローラー設定"
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr "ネットプレイ"
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr "チート"
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr "RetroAchievements"
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr "設定"
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr "バージョン情報"
@@ -483,71 +483,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr "対応ゲームを表示"
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr "設定"
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr "ゲーム"
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr "解像度:"
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr "SSAAダウンスケール"
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr "整数倍スケーリング"
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr "全画面表示"
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr "ワイド画面(伸ばす)"
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr "垂直同期(VSync"
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr "CRTシェーダーを適用"
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr "N64のCPUをオーバークロック(不具合の原因になることがあります)"
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr "拡張パックを無効にする"
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr "巻き戻しを有効にする"
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr "UNFLoaderをエミュレート"
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr "VRUをエミュレート"
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr "UI"
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr "テーマ:"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr "システム"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr "ダーク"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr "ライト"
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
+51 -21
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: gopher64\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: 2026-05-11 12:00+0000\n"
"Last-Translator: \n"
"Language-Team: Dutch (Netherlands)\n"
@@ -47,37 +47,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr "Doneren (via GitHub)"
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr "Lokaal spel"
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr "Controllerconfiguratie"
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr "Netplay"
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr "Cheats"
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr "RetroAchievements"
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr "Instellingen"
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr "Over"
@@ -486,71 +486,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr "Ondersteunde spellen bekijken"
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr "Instellingen"
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr "Spel"
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr "Resolutie:"
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr "SSAA-downscaling"
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr "Schalen in hele getallen"
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr "Volledig scherm"
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr "Breedbeeld (uitgerekt)"
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr "VSync"
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr "CRT-shader toepassen"
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr "N64-CPU overklokken (kan bugs veroorzaken)"
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr "Expansion Pak uitschakelen"
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr "Terugspoelen inschakelen"
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr "UNFLoader emuleren"
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr "VRU emuleren"
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr "Interface"
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr "Thema:"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr "Systeem"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr "Donker"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr "Licht"
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
+57 -27
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: 2026-05-11 18:11-3000\n"
"Last-Translator: EDUARDO CARVALHO <eduardotcarvalho@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -10,7 +10,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/ui/gui/about_page.slint:17
msgctxt "NewVersionButton"
@@ -47,37 +47,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr "Doações (via GitHub)"
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr "Jogo Local"
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr "Configurar Controle"
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr "Netplay"
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr "Trapaças"
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr "RetroAchievements"
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr "Configurações"
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr "Sobre"
@@ -180,7 +180,7 @@ msgstr "Abrir ROM"
#: src/ui/gui/localgame_page.slint:37
msgctxt "LocalGame"
msgid "Open Saves Folder"
msgstr "Abrir Partes de Saves"
msgstr "Abrir Pasta de Saves"
#: src/ui/gui/localgame_page.slint:54
msgctxt "LocalGame"
@@ -200,7 +200,7 @@ msgstr "Nome da Sessão:"
#: src/ui/gui/netplay_create.slint:26
msgctxt "NetplayCreate"
msgid "Enter session name"
msgstr "Insira nome da sessão:"
msgstr "Insira nome da sessão"
#: src/ui/gui/netplay_create.slint:36
msgctxt "NetplayCreate"
@@ -364,7 +364,7 @@ msgstr "Nome do Jogo:"
#: src/ui/gui/netplay_wait.slint:45
msgctxt "NetplayWait"
msgid "Player 1:"
msgstr "Jogador 1"
msgstr "Jogador 1:"
#: src/ui/gui/netplay_wait.slint:49
msgctxt "NetplayWait"
@@ -399,8 +399,8 @@ msgid ""
"Alt+]."
msgstr ""
"Definir o atraso de entrada muito baixo causará lag no jogo.\n"
"Você pode diminuir o atraso de entrada no jogo pressionando Alt+[ e "
"aumentá-lo com Alt+]."
"Você pode diminuir o atraso de entrada no jogo pressionando Alt+[ e aumentá-"
"lo com Alt+]."
#: src/ui/gui/netplay_wait.slint:101
msgctxt "NetplayWait"
@@ -487,71 +487,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr "Ver Jogos com Suporte"
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr "Configurações"
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr "Jogo"
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr "Resolução:"
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr "Redução de SSAA"
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr "Proporção Íntegra"
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr "Tela Cheia"
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr "Widescreen (esticar)"
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr "VSync"
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr "Aplicar filtro de CRT"
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr "Overclock da CPU do N64 (pode causar bugs)"
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr "Desabilitar Expansion Pak"
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr "Habilitar rebobinamento"
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr "Emular UNFLoader"
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr "Emular VRU"
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr "Interface"
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr "Tema:"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr "Sistema"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr "Escuro"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr "Claro"
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
+53 -22
View File
@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: gopher64\n"
"POT-Creation-Date: 2026-06-16 12:26+0000\n"
"POT-Creation-Date: 2026-06-30 09:43+0000\n"
"PO-Revision-Date: 2026-05-11 12:00+0000\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
@@ -10,7 +10,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: src/ui/gui/about_page.slint:17
msgctxt "NewVersionButton"
@@ -47,37 +48,37 @@ msgctxt "About"
msgid "Donate (via GitHub)"
msgstr "Пожертвовать (через GitHub)"
#: src/ui/gui/appwindow.slint:148
#: src/ui/gui/appwindow.slint:164
msgctxt "Menu"
msgid "Local Game"
msgstr "Локальная игра"
#: src/ui/gui/appwindow.slint:152
#: src/ui/gui/appwindow.slint:168
msgctxt "Menu"
msgid "Controller Config"
msgstr "Настройка контроллера"
#: src/ui/gui/appwindow.slint:156
#: src/ui/gui/appwindow.slint:172
msgctxt "Menu"
msgid "Netplay"
msgstr "Сетевая игра"
#: src/ui/gui/appwindow.slint:160
#: src/ui/gui/appwindow.slint:176
msgctxt "Menu"
msgid "Cheats"
msgstr "Читы"
#: src/ui/gui/appwindow.slint:164
#: src/ui/gui/appwindow.slint:180
msgctxt "Menu"
msgid "RetroAchievements"
msgstr "RetroAchievements"
#: src/ui/gui/appwindow.slint:168
#: src/ui/gui/appwindow.slint:184
msgctxt "Menu"
msgid "Settings"
msgstr "Настройки"
#: src/ui/gui/appwindow.slint:172
#: src/ui/gui/appwindow.slint:188
msgctxt "Menu"
msgid "About"
msgstr "О программе"
@@ -485,71 +486,101 @@ msgctxt "RetroAchievements"
msgid "View Supported Games"
msgstr "Просмотреть поддерживаемые игры"
#: src/ui/gui/settings_page.slint:24
#: src/ui/gui/settings_page.slint:25
msgctxt "Settings"
msgid "Settings"
msgstr "Настройки"
#: src/ui/gui/settings_page.slint:35
#: src/ui/gui/settings_page.slint:32
msgctxt "Settings"
msgid "Game"
msgstr "Игра"
#: src/ui/gui/settings_page.slint:38
msgctxt "Settings"
msgid "Resolution:"
msgstr "Разрешение:"
#: src/ui/gui/settings_page.slint:49
#: src/ui/gui/settings_page.slint:51
msgctxt "Settings"
msgid "SSAA downscaling"
msgstr "SSAA даунскейлинг"
#: src/ui/gui/settings_page.slint:57
#: src/ui/gui/settings_page.slint:59
msgctxt "Settings"
msgid "Integer Scaling"
msgstr "Целочисленное масштабирование"
#: src/ui/gui/settings_page.slint:65
#: src/ui/gui/settings_page.slint:67
msgctxt "Settings"
msgid "Fullscreen"
msgstr "Полноэкранный режим"
#: src/ui/gui/settings_page.slint:73
#: src/ui/gui/settings_page.slint:75
msgctxt "Settings"
msgid "Widescreen (stretch)"
msgstr "Широкоэкранный режим (растянуто)"
#: src/ui/gui/settings_page.slint:81
#: src/ui/gui/settings_page.slint:83
msgctxt "Settings"
msgid "VSync"
msgstr "Вертикальная синхронизация"
#: src/ui/gui/settings_page.slint:89
#: src/ui/gui/settings_page.slint:91
msgctxt "Settings"
msgid "Apply CRT shader"
msgstr "Применить шейдер ЭЛТ"
#: src/ui/gui/settings_page.slint:101
#: src/ui/gui/settings_page.slint:103
msgctxt "Settings"
msgid "Overclock N64 CPU (may cause bugs)"
msgstr "Разгон процессора N64 (может вызвать ошибки)"
#: src/ui/gui/settings_page.slint:109
#: src/ui/gui/settings_page.slint:111
msgctxt "Settings"
msgid "Disable Expansion Pak"
msgstr "Отключить Expansion Pak"
#: src/ui/gui/settings_page.slint:117
#: src/ui/gui/settings_page.slint:119
msgctxt "Settings"
msgid "Enable Rewind"
msgstr "Включить перемотку назад"
#: src/ui/gui/settings_page.slint:125
#: src/ui/gui/settings_page.slint:127
msgctxt "Settings"
msgid "Emulate UNFLoader"
msgstr "Эмулировать UNFLoader"
#: src/ui/gui/settings_page.slint:133
#: src/ui/gui/settings_page.slint:135
msgctxt "Settings"
msgid "Emulate VRU"
msgstr "Эмулировать VRU"
#: src/ui/gui/settings_page.slint:144
msgctxt "Settings"
msgid "UI"
msgstr "Интерфейс"
#: src/ui/gui/settings_page.slint:150
msgctxt "Settings"
msgid "Theme:"
msgstr "Тема:"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "System"
msgstr "Система"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Dark"
msgstr "Тёмная"
#: src/ui/gui/settings_page.slint:154
msgctxt "Settings"
msgid "Light"
msgstr "Светлая"
#: src/ui/gui/vru_dialog.slint:7
msgctxt "VruDialog"
msgid "What Would You Like To Say?"
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

+8 -5
View File
@@ -335,11 +335,11 @@ static void rdp_new_processor() {
gfx_info.RDRAM_SIZE / 2, flags);
g_tmem = processor->get_tmem();
if (!g_tmem) {
printf("Failed to get tmem\n");
LOGE("Failed to get tmem\n");
}
g_hidden_rdram = processor->begin_read_hidden_rdram();
if (!g_hidden_rdram) {
printf("Failed to get hidden_rdram\n");
LOGE("Failed to get hidden_rdram\n");
}
sync_signal = 0;
@@ -376,7 +376,7 @@ void rdp_init(void *_window, GFX_INFO _gfx_info, const void *font,
SDL_SyncWindow(window);
bool result = SDL_AddEventWatch(sdl_event_filter, nullptr);
if (!result) {
printf("Could not add event watch.\n");
LOGE("Could not add event watch.\n");
return;
}
@@ -692,7 +692,10 @@ void rdp_update_screen() {
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) {
return;
}
wsi->end_frame();
if (!wsi->end_frame()) {
LOGE("End frame failed\n");
SDL_PumpEvents(); // For Android to trigger pause event
}
wsi->begin_frame();
}
@@ -787,7 +790,7 @@ uint32_t pixel_size(uint32_t pixel_type, uint32_t area) {
case 3:
return area * 4;
default:
printf("Invalid pixel size: %u\n", pixel_type);
LOGE("Invalid pixel size: %u\n", pixel_type);
return 0;
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ uint32_t SDL_WSIPlatform::get_surface_height() {
bool SDL_WSIPlatform::alive(Vulkan::WSI &wsi) { return true; }
void SDL_WSIPlatform::poll_input() {}
void SDL_WSIPlatform::poll_input() { SDL_PumpEvents(); }
void SDL_WSIPlatform::poll_input_async(Granite::InputTrackerHandler *handler) {}
+1 -1
View File
@@ -159,7 +159,7 @@ void ra_welcome(const char **game_title, const char **game_image_url) {
int message_length = snprintf(
buffer, sizeof(buffer), "%s\nMode: %s\n", game->title,
rc_client_get_hardcore_enabled(g_client) ? "Hardcore" : "Softcore");
rc_client_get_hardcore_enabled(g_client) ? "Hardcore" : "Casual");
if (summary.num_core_achievements != 0) {
snprintf(buffer + message_length, sizeof(buffer) - message_length,
+1 -1
View File
@@ -1,2 +1,2 @@
[toolchain]
channel = "1.96.0"
channel = "1.96.1"
+1 -1
View File
@@ -59,7 +59,7 @@ pub fn process(device: &mut device::Device, channel: usize) {
let input = if let Some(netplay) = &mut device.netplay {
netplay.inputs[channel].0
} else {
ui::input::get(&mut device.ui, channel, device.speed_limiter.frame_counter)
ui::input::get(&mut device.ui, channel)
};
device.pif.ram[offset..offset + 4].copy_from_slice(&input.data.to_ne_bytes());
-1
View File
@@ -118,7 +118,6 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
pub fn update_screen(device: &mut device::Device) {
if !netplay::in_rollback(device.netplay.as_ref()) {
ui::video::render_frame();
unsafe { sdl3_sys::events::SDL_PumpEvents() };
}
let (speed_limiter_toggled, paused) = ui::video::check_callback(device);
+20 -9
View File
@@ -22,6 +22,8 @@ pub struct Args {
#[arg(short, long)]
pub fullscreen: bool,
#[arg(long)]
pub widescreen: bool,
#[arg(long)]
pub overclock: Option<bool>,
#[arg(long)]
pub disable_expansion_pak: Option<bool>,
@@ -128,8 +130,6 @@ pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> {
ui::sdl_hints();
if let Some(game) = args.game {
ui::disable_auto_update_joysticks();
let file_path = std::path::Path::new(&game).to_path_buf();
let Some(rom_contents) = device::get_rom_contents(&file_path) else {
return Err(Error::other(format!(
@@ -163,15 +163,22 @@ pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> {
let mut device = device::Device::new(true);
device.ui.config.recent_roms.retain(|x| *x != game);
device.ui.config.recent_roms.insert(0, game);
device.ui.config.recent_roms.truncate(5);
device.ui.config.ui.recent_roms.retain(|x| *x != game);
device.ui.config.ui.recent_roms.insert(0, game);
device.ui.config.ui.recent_roms.truncate(5);
if args.fullscreen {
device.ui.video.fullscreen = true;
} else {
device.ui.video.fullscreen = device.ui.config.video.fullscreen;
}
if args.widescreen {
device.ui.video.widescreen = true;
} else {
device.ui.video.widescreen = device.ui.config.video.widescreen;
}
let overclock = args
.overclock
.unwrap_or(device.ui.config.emulation.overclock);
@@ -286,11 +293,11 @@ pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> {
let mut config = ui::config::Config::new();
if let Some(profile) = args.configure_input_profile {
ui::input::configure_input_profile(
ui::input_profile::configure_input_profile(
&mut config,
profile,
args.use_dinput,
args.deadzone.unwrap_or(ui::input::DEADZONE_DEFAULT),
args.deadzone.unwrap_or(ui::input_profile::DEADZONE_DEFAULT),
);
ui::sdl_close();
@@ -334,8 +341,10 @@ pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> {
#[cfg(feature = "gui")]
{
let app = ui::gui::AppWindow::new().unwrap();
let no_intro_map =
std::sync::Arc::new(tokio::sync::Mutex::new(rustc_hash::FxHashMap::default()));
set_app_id();
ui::gui::app_window(&app, false);
ui::gui::app_window(&app, false, no_intro_map);
}
}
@@ -380,7 +389,9 @@ fn android_main(app: slint::android::AndroidApp) {
std::fs::create_dir_all(dirs.data_dir.join("saves")).unwrap();
std::fs::create_dir_all(dirs.data_dir.join("states")).unwrap();
ui::gui::app_window(&app_window, true);
let no_intro_map =
std::sync::Arc::new(tokio::sync::Mutex::new(rustc_hash::FxHashMap::default()));
ui::gui::app_window(&app_window, true, no_intro_map);
close_tx.send(()).unwrap();
*android::WEAK_SLINT_WINDOW.lock().unwrap() = None;
*android::ANDROID_APP.lock().unwrap() = None;
+6 -19
View File
@@ -1,4 +1,5 @@
use crate::device;
use crate::savestates;
use crate::ui;
use sha2::digest::Digest;
@@ -269,7 +270,7 @@ pub fn process_requests(
if let Some(request) = device.netplay.as_mut().unwrap().requests.pop_front() {
match request {
ggrs::GgrsRequest::SaveGameState { cell, frame } => {
//savestates::create_savestate(device, true, Some(frame));
savestates::create_savestate(device, true, Some(frame));
let mut hasher = sha2::Sha256::new();
for reg in device.cpu.cop0.regs.as_ref() {
@@ -280,8 +281,8 @@ pub fn process_requests(
}
ggrs::GgrsRequest::LoadGameState { cell, frame: _ } => {
eprintln!("attempting to load game state");
if let Some(_frame) = cell.load() {
// savestates::load_savestate(device, true, Some(frame));
if let Some(frame) = cell.load() {
savestates::load_savestate(device, true, Some(frame));
}
}
ggrs::GgrsRequest::AdvanceFrame { inputs } => {
@@ -339,26 +340,13 @@ fn process_netplay(device: &mut device::Device) {
fn advance_frame(device: &mut device::Device) {
let netplay = device.netplay.as_mut().unwrap();
let local_input = if netplay.session.current_frame() > netplay.session.max_prediction() as i32 {
ui::input::get(&mut device.ui, 0, device.speed_limiter.frame_counter)
} else {
//workaround for disabled rollback
ui::input::InputData::default()
};
let local_input = ui::input::get(&mut device.ui, 0);
let local_handle = *netplay.session.local_player_handles().first().unwrap();
netplay
.session
.add_local_input(local_handle, local_input)
.unwrap();
// avoid rollback
while !netplay.disconnected
&& netplay.session.current_frame() > netplay.session.confirmed_frame()
&& netplay.session.confirmed_frame() != ggrs::NULL_FRAME
{
poll_clients(netplay);
}
if netplay.disconnected {
netplay.requests.push_back(ggrs::GgrsRequest::AdvanceFrame {
inputs: vec![
@@ -486,7 +474,6 @@ pub fn init(
message_timer = std::time::Instant::now();
}
unsafe { sdl3_sys::events::SDL_PumpEvents() };
ui::video::render_frame();
ui::video::update_screen();
std::thread::sleep(std::time::Duration::from_millis(10));
@@ -505,7 +492,7 @@ pub fn init(
.with_fps(if pal { 50 } else { 60 })
.unwrap()
.with_desync_detection_mode(ggrs::DesyncDetection::On { interval: 60 })
.with_max_prediction_window(16)
.with_max_prediction_window(0)
.with_disconnect_timeout(std::time::Duration::from_secs(if cfg!(debug_assertions) {
10
} else {
+3 -12
View File
@@ -7,6 +7,7 @@ pub mod config;
#[cfg(feature = "gui")]
pub mod gui;
pub mod input;
pub mod input_profile;
#[cfg(feature = "gui")]
pub mod netplay;
#[cfg(feature = "gui")]
@@ -49,7 +50,6 @@ unsafe impl Sync for Audio {}
#[derive(Default)]
pub struct Input {
pub keyboard_state: *const bool,
pub last_polled: u64,
pub controllers: [input::Controllers; 4],
}
@@ -68,6 +68,7 @@ pub struct Storage {
pub struct Video {
pub window: *mut sdl3_sys::video::SDL_Window,
pub fullscreen: bool,
pub widescreen: bool,
pub fps_tx: Option<tokio::sync::mpsc::UnboundedSender<bool>>,
pub fps_rx: Option<tokio::sync::mpsc::UnboundedReceiver<bool>>,
pub vis_tx: Option<tokio::sync::mpsc::UnboundedSender<bool>>,
@@ -120,16 +121,6 @@ pub fn sdl_hints() {
}
}
pub fn disable_auto_update_joysticks() {
unsafe {
let hint = std::ffi::CString::new("0").unwrap();
sdl3_sys::everything::SDL_SetHint(
sdl3_sys::everything::SDL_HINT_AUTO_UPDATE_JOYSTICKS,
hint.as_ptr(),
);
}
}
pub fn sdl_init(flag: sdl3_sys::init::SDL_InitFlags) {
unsafe {
if sdl3_sys::init::SDL_WasInit(flag) == 0 && !sdl3_sys::init::SDL_InitSubSystem(flag) {
@@ -195,7 +186,6 @@ impl Ui {
let (vis_tx, vis_rx) = tokio::sync::mpsc::unbounded_channel();
Ui {
input: Input {
last_polled: 0,
controllers: [
input::Controllers {
game_controller: std::ptr::null_mut(),
@@ -278,6 +268,7 @@ impl Ui {
video: Video {
window: std::ptr::null_mut(),
fullscreen: false,
widescreen: false,
fps_tx: Some(fps_tx),
fps_rx: Some(fps_rx),
vis_tx: Some(vis_tx),
+6 -2
View File
@@ -3,17 +3,21 @@ use crate::ui::gui::AppWindow;
use crate::{cheats, device};
use slint::ComponentHandle;
pub fn cheats_window(app: &AppWindow) {
pub fn cheats_window(
app: &AppWindow,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let weak = app.as_weak();
app.on_cheats_select_rom_clicked(move |rom_dir| {
let select_rom = ui::gui::select_rom(rom_dir);
let weak = weak.clone();
let no_intro_map = no_intro_map.clone();
tokio::spawn(async move {
if let Some(file) = select_rom.await
&& let Some(rom_contents) = device::get_rom_contents(&file)
{
let game_crc = ui::storage::get_game_crc(&rom_contents);
let game_name = ui::storage::get_game_name(&rom_contents);
let game_name = ui::gui::get_nointro_name(&rom_contents, no_intro_map).await;
weak.upgrade_in_event_loop(move |handle| {
handle.set_cheat_game_name(game_name.into());
})
+32 -18
View File
@@ -1,34 +1,36 @@
use crate::ui;
#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct InputKeyButton {
pub enabled: bool,
pub id: i32,
}
#[derive(PartialEq, Copy, Clone, serde::Serialize, serde::Deserialize)]
#[derive(PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct InputControllerAxis {
pub enabled: bool,
pub id: i32,
pub axis: i16,
pub initial_state: i16,
}
#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct InputJoystickHat {
pub enabled: bool,
pub id: i32,
pub direction: u8,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub enum InputItem {
Key(InputKeyButton),
ControllerButton(InputKeyButton),
ControllerAxis(InputControllerAxis),
JoystickButton(InputKeyButton),
JoystickHat(InputJoystickHat),
JoystickAxis(InputControllerAxis),
}
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct InputProfile {
pub keys: [InputKeyButton; ui::input::PROFILE_SIZE],
pub controller_buttons: [InputKeyButton; ui::input::PROFILE_SIZE],
pub controller_axis: [InputControllerAxis; ui::input::PROFILE_SIZE],
pub joystick_buttons: [InputKeyButton; ui::input::PROFILE_SIZE],
pub joystick_hat: [InputJoystickHat; ui::input::PROFILE_SIZE],
pub joystick_axis: [InputControllerAxis; ui::input::PROFILE_SIZE],
pub inputs: [[Option<InputItem>; 2]; ui::input_profile::PROFILE_SIZE],
pub dinput: bool,
pub deadzone: i32,
}
@@ -69,13 +71,19 @@ pub struct Cheats {
pub cheats: rustc_hash::FxHashMap<String, rustc_hash::FxHashMap<String, Option<String>>>,
}
#[derive(Default, serde::Serialize, serde::Deserialize)]
pub struct Ui {
pub theme: i32,
pub rom_dir: std::path::PathBuf,
pub recent_roms: Vec<String>,
}
#[derive(Default, serde::Serialize, serde::Deserialize)]
pub struct Config {
pub input: Input,
pub video: Video,
pub emulation: Emulation,
pub rom_dir: std::path::PathBuf,
pub recent_roms: Vec<String>,
pub ui: Ui,
#[serde(skip)]
write_to_disk: bool,
}
@@ -154,7 +162,10 @@ impl Config {
}
let mut input_profiles = std::collections::BTreeMap::new();
input_profiles.insert("default".to_string(), ui::input::get_default_profile());
input_profiles.insert(
"default".to_string(),
ui::input_profile::get_default_profile(),
);
Config {
input: input_data.unwrap_or(Input {
input_profile_binding: [
@@ -186,8 +197,11 @@ impl Config {
usb: false,
rewind: false,
},
rom_dir: std::path::PathBuf::new(),
recent_roms: Vec::new(),
ui: Ui {
theme: 0,
rom_dir: std::path::PathBuf::new(),
recent_roms: Vec::new(),
},
write_to_disk: true,
}
}
+79 -6
View File
@@ -1,3 +1,4 @@
use crate::device;
use crate::retroachievements;
use crate::ui;
#[cfg(target_os = "android")]
@@ -112,6 +113,7 @@ fn local_game_window(app: &AppWindow, config: &ui::config::Config) {
app.set_recent_roms(slint::ModelRc::from(std::rc::Rc::new(
slint::VecModel::from(
config
.ui
.recent_roms
.iter()
.filter(|x| rom_exists(x))
@@ -179,6 +181,7 @@ fn settings_window(app: &AppWindow, config: &ui::config::Config) {
app.set_widescreen(config.video.widescreen);
app.set_vsync(config.video.vsync);
app.set_apply_crt_shader(config.video.crt);
app.set_theme(config.ui.theme);
app.set_overclock_n64_cpu(config.emulation.overclock);
app.set_disable_expansion_pak(config.emulation.disable_expansion_pak);
app.set_emulate_usb(config.emulation.usb);
@@ -192,7 +195,7 @@ fn settings_window(app: &AppWindow, config: &ui::config::Config) {
};
app.set_resolution(combobox_value);
if let Some(rom_dir_str) = config.rom_dir.to_str() {
if let Some(rom_dir_str) = config.ui.rom_dir.to_str() {
app.set_rom_dir(rom_dir_str.into());
}
}
@@ -344,7 +347,7 @@ fn controller_window(app: &AppWindow, config: &ui::config::Config) {
app.on_input_profile_button_clicked(move || {
weak_app
.upgrade_in_event_loop(move |handle| {
handle.set_input_deadzone(ui::input::DEADZONE_DEFAULT);
handle.set_input_deadzone(ui::input_profile::DEADZONE_DEFAULT);
handle.set_input_profile_name(String::new().into());
handle.set_input_dinput(false);
handle.set_show_input_profile(true);
@@ -444,13 +447,14 @@ fn controller_window(app: &AppWindow, config: &ui::config::Config) {
pub fn save_settings(app: &AppWindow) {
let mut config = ui::config::Config::new();
config.rom_dir = app.get_rom_dir().to_string().into();
config.ui.rom_dir = app.get_rom_dir().to_string().into();
config.video.integer_scaling = app.get_integer_scaling();
config.video.ssaa = app.get_ssaa();
config.video.fullscreen = app.get_fullscreen();
config.video.widescreen = app.get_widescreen();
config.video.vsync = app.get_vsync();
config.video.crt = app.get_apply_crt_shader();
config.ui.theme = app.get_theme();
config.emulation.overclock = app.get_overclock_n64_cpu();
config.emulation.disable_expansion_pak = app.get_disable_expansion_pak();
config.emulation.usb = app.get_emulate_usb();
@@ -521,7 +525,16 @@ fn about_window(app: &AppWindow) {
}
}
pub fn app_window(app: &AppWindow, is_android: bool) {
pub fn app_window(
app: &AppWindow,
is_android: bool,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let no_intro_map_clone = no_intro_map.clone();
tokio::spawn(async move {
load_no_intro(no_intro_map_clone).await;
});
retroachievements::init_client(false, false, false);
app.set_is_android(is_android);
about_window(app);
@@ -532,8 +545,8 @@ pub fn app_window(app: &AppWindow, is_android: bool) {
controller_window(app, &config);
local_game_window(app, &config);
}
ui::netplay::netplay_window(app);
ui::cheats::cheats_window(app);
ui::netplay::netplay_window(app, no_intro_map.clone());
ui::cheats::cheats_window(app, no_intro_map);
#[cfg(not(target_os = "android"))]
{
@@ -657,6 +670,66 @@ pub fn update_recent_roms(app: &AppWindow, file_path: std::path::PathBuf) {
app.set_recent_roms(slint::ModelRc::from(std::rc::Rc::new(recent_roms)));
}
pub async fn get_nointro_name(
rom: &[u8],
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) -> String {
let hash = device::cart::rom::calculate_hash(rom).to_lowercase();
if let Some(name) = no_intro_map.lock().await.get(&hash) {
name.clone()
} else {
ui::storage::get_game_name(rom)
}
}
async fn load_no_intro(
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let mut reader = quick_xml::Reader::from_str(include_str!(
"../../data/ui/Nintendo - Nintendo 64 (DB Export) (20260609-194259).xml"
));
let mut current_game = String::new();
let mut map = no_intro_map.lock().await;
let mut xml_version = quick_xml::XmlVersion::Implicit1_0;
loop {
match reader.read_event() {
Ok(quick_xml::events::Event::Decl(e)) => {
if let Ok(version) = e.xml_version() {
xml_version = version;
}
}
Ok(quick_xml::events::Event::Start(e)) => {
if e.name().as_ref() == b"game"
&& let Ok(Some(name_attribute)) = e.try_get_attribute("name")
&& let Ok(normalized_value) = name_attribute.normalized_value(xml_version)
{
current_game = normalized_value.into_owned();
}
}
Ok(quick_xml::events::Event::End(e)) => {
if e.name().as_ref() == b"game" {
current_game.clear();
}
}
Ok(quick_xml::events::Event::Empty(e)) => {
if e.name().as_ref() == b"file"
&& let Ok(Some(format_attribute)) = e.try_get_attribute("format")
&& let Ok(normalized_value) = format_attribute.normalized_value(xml_version)
&& normalized_value.as_ref() == "BigEndian"
&& let Ok(Some(sha256_attribute)) = e.try_get_attribute("sha256")
&& let Ok(normalized_sha256) = sha256_attribute.normalized_value(xml_version)
&& !current_game.is_empty()
{
map.insert(normalized_sha256.to_lowercase(), current_game.clone());
}
}
Err(e) => panic!("Error at position {}: {:?}", reader.error_position(), e),
Ok(quick_xml::events::Event::Eof) => break,
_ => (),
}
}
}
pub async fn select_rom(rom_dir: slint::SharedString) -> Option<std::path::PathBuf> {
#[cfg(target_os = "android")]
return ui::android::select_rom(rom_dir).await;
+17 -1
View File
@@ -61,10 +61,11 @@ export component AppWindow inherits Window {
in-out property ra_challenge <=> RAData.challenge;
in-out property ra_leaderboard <=> RAData.leaderboard;
in-out property ra_rich_presence <=> RAData.rich_presence;
in-out property ra_softcore_only <=> RAData.ra_softcore_only;
in-out property ra_casual_only <=> RAData.ra_casual_only;
out property ra_not_logged_in <=> RAData.not_logged_in;
in-out property integer_scaling <=> SettingsData.integer_scaling;
in-out property ssaa <=> SettingsData.ssaa;
in-out property theme <=> SettingsData.theme;
in-out property fullscreen <=> SettingsData.fullscreen;
in-out property widescreen <=> SettingsData.widescreen;
in-out property vsync <=> SettingsData.vsync;
@@ -131,6 +132,21 @@ export component AppWindow inherits Window {
private property <length> safe-bottom: root.safe-area-insets.bottom;
private property <length> safe-width: root.width - root.safe-left - root.safe-right;
private property <length> safe-height: root.height - root.safe-top - root.safe-bottom;
function apply_theme() {
if (root.theme == 1) {
Palette.color-scheme = ColorScheme.dark;
} else if (root.theme == 2) {
Palette.color-scheme = ColorScheme.light;
} else {
Palette.color-scheme = ColorScheme.unknown;
}
}
init => {
apply_theme();
}
changed theme => {
apply_theme();
}
min-width: 320px;
min-height: 240px;
+2 -2
View File
@@ -12,7 +12,7 @@ export global RAData {
in-out property <bool> rich_presence;
in-out property <bool> ra_logging_in;
in-out property <bool> ra_show_profile;
in-out property <bool> ra_softcore_only;
in-out property <bool> ra_casual_only;
in-out property <string> ra_username;
in-out property <string> ra_password;
in-out property <string> current_user_message;
@@ -47,7 +47,7 @@ export component RetroAchievements inherits Page {
ra_toggled(RAData.enabled,RAData.hardcore,RAData.challenge,RAData.leaderboard,RAData.rich_presence);
}
}
if !RAData.ra_softcore_only: Switch {
if !RAData.ra_casual_only: Switch {
text: @tr("Hardcore mode");
checked: RAData.hardcore;
enabled: RAData.enabled;
+131 -105
View File
@@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { ComboBox, HorizontalBox, VerticalBox, Switch } from "std-widgets.slint";
import { GroupBox, ComboBox, HorizontalBox, VerticalBox, Switch } from "std-widgets.slint";
import { Page } from "page.slint";
export global SettingsData {
@@ -14,6 +14,7 @@ export global SettingsData {
in-out property <bool> overclock_n64_cpu;
in-out property <bool> disable_expansion_pak;
in-out property <int> resolution;
in-out property <int> theme;
in-out property <bool> emulate_usb;
in-out property <bool> rewind;
in-out property <bool> emulate_vru;
@@ -23,117 +24,142 @@ export global SettingsData {
export component Settings inherits Page {
title: @tr("Settings");
VerticalBox {
alignment: start;
HorizontalBox {
alignment: center;
VerticalBox {
alignment: start;
HorizontalBox {
HorizontalBox {
alignment: center;
VerticalBox {
alignment: start;
GroupBox {
title: @tr("Game");
VerticalBox {
alignment: start;
Text {
text: @tr("Resolution:");
vertical-alignment: center;
HorizontalBox {
alignment: start;
Text {
text: @tr("Resolution:");
vertical-alignment: center;
}
ComboBox {
model: ["1x", "2x", "4x", "8x"];
current-index: SettingsData.resolution;
selected => {
SettingsData.resolution = self.current-index;
}
}
}
ComboBox {
model: ["1x", "2x", "4x", "8x"];
current-index: SettingsData.resolution;
selected => {
SettingsData.resolution = self.current-index;
Switch {
text: @tr("SSAA downscaling");
checked: SettingsData.ssaa;
toggled => {
SettingsData.ssaa = self.checked;
}
}
Switch {
text: @tr("Integer Scaling");
checked: SettingsData.integer_scaling;
toggled => {
SettingsData.integer_scaling = self.checked;
}
}
Switch {
text: @tr("Fullscreen");
checked: SettingsData.fullscreen;
toggled => {
SettingsData.fullscreen = self.checked;
}
}
Switch {
text: @tr("Widescreen (stretch)");
checked: SettingsData.widescreen;
toggled => {
SettingsData.widescreen = self.checked;
}
}
Switch {
text: @tr("VSync");
checked: SettingsData.vsync;
toggled => {
SettingsData.vsync = self.checked;
}
}
Switch {
text: @tr("Apply CRT shader");
checked: SettingsData.apply_crt_shader;
toggled => {
SettingsData.apply_crt_shader = self.checked;
}
}
Rectangle {
height: 20px;
}
Switch {
text: @tr("Overclock N64 CPU (may cause bugs)");
checked: SettingsData.overclock_n64_cpu;
toggled => {
SettingsData.overclock_n64_cpu = self.checked;
}
}
Switch {
text: @tr("Disable Expansion Pak");
checked: SettingsData.disable_expansion_pak;
toggled => {
SettingsData.disable_expansion_pak = self.checked;
}
}
Switch {
text: @tr("Enable Rewind");
checked: SettingsData.rewind;
toggled => {
SettingsData.rewind = self.checked;
}
}
Switch {
text: @tr("Emulate UNFLoader");
checked: SettingsData.emulate_usb;
toggled => {
SettingsData.emulate_usb = self.checked;
}
}
Switch {
text: @tr("Emulate VRU");
checked: SettingsData.emulate_vru;
toggled => {
SettingsData.emulate_vru = self.checked;
}
}
}
Switch {
text: @tr("SSAA downscaling");
checked: SettingsData.ssaa;
toggled => {
SettingsData.ssaa = self.checked;
}
GroupBox {
title: @tr("UI");
VerticalBox {
alignment: start;
HorizontalBox {
alignment: start;
Text {
text: @tr("Theme:");
vertical-alignment: center;
}
ComboBox {
model: [@tr("System"), @tr("Dark"), @tr("Light")];
current-index: SettingsData.theme;
selected => {
SettingsData.theme = self.current-index;
}
}
}
}
Switch {
text: @tr("Integer Scaling");
checked: SettingsData.integer_scaling;
toggled => {
SettingsData.integer_scaling = self.checked;
}
}
Switch {
text: @tr("Fullscreen");
checked: SettingsData.fullscreen;
toggled => {
SettingsData.fullscreen = self.checked;
}
}
Switch {
text: @tr("Widescreen (stretch)");
checked: SettingsData.widescreen;
toggled => {
SettingsData.widescreen = self.checked;
}
}
Switch {
text: @tr("VSync");
checked: SettingsData.vsync;
toggled => {
SettingsData.vsync = self.checked;
}
}
Switch {
text: @tr("Apply CRT shader");
checked: SettingsData.apply_crt_shader;
toggled => {
SettingsData.apply_crt_shader = self.checked;
}
}
Rectangle {
height: 20px;
}
Switch {
text: @tr("Overclock N64 CPU (may cause bugs)");
checked: SettingsData.overclock_n64_cpu;
toggled => {
SettingsData.overclock_n64_cpu = self.checked;
}
}
Switch {
text: @tr("Disable Expansion Pak");
checked: SettingsData.disable_expansion_pak;
toggled => {
SettingsData.disable_expansion_pak = self.checked;
}
}
Switch {
text: @tr("Enable Rewind");
checked: SettingsData.rewind;
toggled => {
SettingsData.rewind = self.checked;
}
}
Switch {
text: @tr("Emulate UNFLoader");
checked: SettingsData.emulate_usb;
toggled => {
SettingsData.emulate_usb = self.checked;
}
}
Switch {
text: @tr("Emulate VRU");
checked: SettingsData.emulate_vru;
toggled => {
SettingsData.emulate_vru = self.checked;
Rectangle {
height: 40px; // so the combobox isn't cut off
}
}
}
+170 -819
View File
File diff suppressed because it is too large Load Diff
+929
View File
@@ -0,0 +1,929 @@
use crate::ui;
const R_DPAD: usize = 0;
const L_DPAD: usize = 1;
const D_DPAD: usize = 2;
const U_DPAD: usize = 3;
pub const START_BUTTON: usize = 4;
pub const Z_TRIG: usize = 5;
pub const B_BUTTON: usize = 6;
const A_BUTTON: usize = 7;
const R_CBUTTON: usize = 8;
pub const L_CBUTTON: usize = 9;
const D_CBUTTON: usize = 10;
const U_CBUTTON: usize = 11;
pub const R_TRIG: usize = 12;
pub const L_TRIG: usize = 13;
pub const AXIS_RIGHT: usize = 14;
pub const AXIS_LEFT: usize = 15;
pub const AXIS_DOWN: usize = 16;
pub const AXIS_UP: usize = 17;
pub const HOTKEY: usize = 18;
pub const PROFILE_SIZE: usize = 19;
pub const DEADZONE_DEFAULT: i32 = 5;
const GATHER_TIME: usize = 5;
pub fn configure_input_profile(
config: &mut ui::config::Config,
profile_name: String,
dinput: bool,
deadzone: i32,
) {
ui::sdl_init(sdl3_sys::init::SDL_INIT_VIDEO);
ui::sdl_init(sdl3_sys::init::SDL_INIT_GAMEPAD);
ui::ttf_init();
if profile_name == "default" {
eprintln!("Profile name cannot be default");
return;
}
if profile_name.is_empty() {
eprintln!("Profile name cannot be empty");
return;
}
let mut profile = if let Some(profile) = config.input.input_profiles.get(&profile_name) {
profile.clone()
} else {
ui::config::InputProfile {
inputs: [const { [None, None] }; PROFILE_SIZE],
dinput,
deadzone,
}
};
let mut open_joysticks: Vec<*mut sdl3_sys::joystick::SDL_Joystick> = Vec::new();
let mut open_controllers: Vec<*mut sdl3_sys::gamepad::SDL_Gamepad> = Vec::new();
for joystick in ui::input::get_joysticks().iter() {
if !dinput {
let controller = unsafe { sdl3_sys::gamepad::SDL_OpenGamepad(*joystick) };
if !controller.is_null() {
open_controllers.push(controller);
}
} else {
let joystick = unsafe { sdl3_sys::joystick::SDL_OpenJoystick(*joystick) };
if !joystick.is_null() {
open_joysticks.push(joystick);
}
}
}
let title = std::ffi::CString::new("configure input profile").unwrap();
let mut window: *mut sdl3_sys::video::SDL_Window = std::ptr::null_mut();
let mut renderer: *mut sdl3_sys::render::SDL_Renderer = std::ptr::null_mut();
#[cfg(target_os = "android")]
let window_flags = sdl3_sys::video::SDL_WINDOW_FULLSCREEN;
#[cfg(not(target_os = "android"))]
let window_flags = sdl3_sys::video::SDL_WindowFlags(0);
if !unsafe {
sdl3_sys::render::SDL_CreateWindowAndRenderer(
title.as_ptr(),
852,
480,
window_flags,
&mut window,
&mut renderer,
)
} {
panic!("Could not create window and renderer")
}
if !unsafe { sdl3_sys::video::SDL_ShowWindow(window) } {
panic!("Could not show window")
}
let text_engine = unsafe { sdl3_ttf_sys::ttf::TTF_CreateRendererTextEngine(renderer) };
let font = unsafe {
let font_bytes = include_bytes!("../../data/ui/RobotoMono-Regular.ttf");
sdl3_ttf_sys::ttf::TTF_OpenFontIO(
sdl3_sys::everything::SDL_IOFromConstMem(
font_bytes.as_ptr() as *const std::ffi::c_void,
font_bytes.len(),
),
true,
12.0,
)
};
set_font_size(window, font);
if draw_profile_screen(window, renderer, text_engine, font, &mut profile, dinput) {
profile.deadzone = deadzone;
profile.dinput = dinput;
config.input.input_profiles.insert(profile_name, profile);
}
for joystick in open_joysticks {
unsafe { sdl3_sys::joystick::SDL_CloseJoystick(joystick) }
}
for controller in open_controllers {
unsafe { sdl3_sys::gamepad::SDL_CloseGamepad(controller) }
}
unsafe {
sdl3_ttf_sys::ttf::TTF_CloseFont(font);
sdl3_ttf_sys::ttf::TTF_DestroyRendererTextEngine(text_engine);
sdl3_sys::render::SDL_DestroyRenderer(renderer);
sdl3_sys::video::SDL_DestroyWindow(window);
}
}
fn set_font_size(window: *mut sdl3_sys::video::SDL_Window, font: *mut sdl3_ttf_sys::ttf::TTF_Font) {
let mut rect: sdl3_sys::rect::SDL_Rect = Default::default();
unsafe {
sdl3_ttf_sys::ttf::TTF_SetFontSize(font, 12.0);
sdl3_sys::video::SDL_GetWindowSafeArea(window, &mut rect)
};
let num_rows = PROFILE_SIZE + 2;
let min_row_height = rect.h / num_rows as i32;
while unsafe { sdl3_ttf_sys::ttf::TTF_GetFontLineSkip(font) } < min_row_height {
unsafe {
let font_size = sdl3_ttf_sys::ttf::TTF_GetFontSize(font);
sdl3_ttf_sys::ttf::TTF_SetFontSize(font, font_size + 0.5);
}
}
}
fn reset_gather(auto_advance: bool) -> (usize, Option<std::time::Instant>) {
if auto_advance {
(GATHER_TIME, Some(std::time::Instant::now()))
} else {
(0, None)
}
}
fn advance_cursor(
selected: &mut (usize, usize),
auto_advance: &mut bool,
) -> (usize, Option<std::time::Instant>) {
selected.0 += 1;
if selected.0 == PROFILE_SIZE {
*auto_advance = false;
}
reset_gather(*auto_advance)
}
fn draw_profile_screen(
window: *mut sdl3_sys::video::SDL_Window,
renderer: *mut sdl3_sys::render::SDL_Renderer,
text_engine: *mut sdl3_ttf_sys::ttf::TTF_TextEngine,
font: *mut sdl3_ttf_sys::ttf::TTF_Font,
profile: &mut ui::config::InputProfile,
dinput: bool,
) -> bool {
let mut selected: (usize, usize) = (0, 0);
let mut auto_advance = dinput && !unsafe { sdl3_sys::keyboard::SDL_HasKeyboard() };
let (mut gather, mut gather_timer) = reset_gather(auto_advance);
loop {
if let Some(timer) = gather_timer
&& timer.elapsed() > std::time::Duration::from_secs(1)
{
gather -= 1;
if gather > 0 {
gather_timer = Some(std::time::Instant::now());
} else {
(gather, gather_timer) = reset_gather(auto_advance);
}
}
let mut event: sdl3_sys::events::SDL_Event = Default::default();
if unsafe { sdl3_sys::events::SDL_WaitEventTimeout(&mut event, 20) } {
match event.event_type() {
sdl3_sys::events::SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED => {
set_font_size(window, font);
}
sdl3_sys::events::SDL_EVENT_WINDOW_CLOSE_REQUESTED => break,
sdl3_sys::events::SDL_EVENT_GAMEPAD_BUTTON_DOWN => {
if gather == 0 {
match sdl3_sys::gamepad::SDL_GamepadButton(
unsafe { event.gbutton.button } as i32
) {
sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_DOWN => {
move_down(&mut selected);
}
sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_UP => {
move_up(&mut selected);
}
sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_LEFT => {
move_left(&mut selected);
}
sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_RIGHT => {
move_right(&mut selected);
}
sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_WEST
| sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_NORTH => {
delete_binding(selected, profile);
}
sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_SOUTH
| sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_EAST
if select_or_save(selected, &mut gather, &mut gather_timer) =>
{
return true;
}
_ => (),
}
} else if !dinput {
profile.inputs[selected.0][selected.1] = Some(
ui::config::InputItem::ControllerButton(ui::config::InputKeyButton {
id: i32::from(unsafe { event.gbutton.button }),
}),
);
(gather, gather_timer) = advance_cursor(&mut selected, &mut auto_advance);
}
}
sdl3_sys::events::SDL_EVENT_KEY_DOWN => {
let scancode = unsafe { event.key }.scancode;
if gather == 0 || scancode == sdl3_sys::scancode::SDL_SCANCODE_AC_BACK {
match scancode {
sdl3_sys::scancode::SDL_SCANCODE_AC_BACK => break,
sdl3_sys::scancode::SDL_SCANCODE_DOWN => {
move_down(&mut selected);
}
sdl3_sys::scancode::SDL_SCANCODE_UP => {
move_up(&mut selected);
}
sdl3_sys::scancode::SDL_SCANCODE_LEFT => {
move_left(&mut selected);
}
sdl3_sys::scancode::SDL_SCANCODE_RIGHT => {
move_right(&mut selected);
}
sdl3_sys::scancode::SDL_SCANCODE_DELETE
| sdl3_sys::scancode::SDL_SCANCODE_BACKSPACE => {
delete_binding(selected, profile);
}
sdl3_sys::scancode::SDL_SCANCODE_RETURN
if select_or_save(selected, &mut gather, &mut gather_timer) =>
{
return true;
}
_ => (),
}
} else {
if scancode != sdl3_sys::scancode::SDL_SCANCODE_LALT
&& scancode != sdl3_sys::scancode::SDL_SCANCODE_RALT
&& !unsafe { event.key }.repeat
{
profile.inputs[selected.0][selected.1] =
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(scancode),
}));
(gather, gather_timer) =
advance_cursor(&mut selected, &mut auto_advance);
}
}
}
sdl3_sys::events::SDL_EVENT_GAMEPAD_AXIS_MOTION => {
let axis_value = unsafe { event.gaxis }.value;
let axis = unsafe { event.gaxis }.axis;
if !dinput
&& gather != 0
&& axis_value.saturating_abs() > (i16::MAX as i32 * 3 / 4) as i16
{
profile.inputs[selected.0][selected.1] =
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(axis),
axis: axis_value.signum(),
initial_state: 0,
},
));
(gather, gather_timer) = advance_cursor(&mut selected, &mut auto_advance);
}
}
sdl3_sys::events::SDL_EVENT_JOYSTICK_BUTTON_DOWN => {
if dinput {
if gather == 0 {
if let Some(ui::config::InputItem::JoystickButton(joystick_button)) =
&profile.inputs[D_DPAD][0]
&& joystick_button.id == unsafe { event.jbutton.button } as i32
{
move_down(&mut selected);
} else if let Some(ui::config::InputItem::JoystickButton(
joystick_button,
)) = &profile.inputs[U_DPAD][0]
&& joystick_button.id == unsafe { event.jbutton.button } as i32
{
move_up(&mut selected);
} else if let Some(ui::config::InputItem::JoystickButton(
joystick_button,
)) = &profile.inputs[L_DPAD][0]
&& joystick_button.id == unsafe { event.jbutton.button } as i32
{
move_left(&mut selected);
} else if let Some(ui::config::InputItem::JoystickButton(
joystick_button,
)) = &profile.inputs[R_DPAD][0]
&& joystick_button.id == unsafe { event.jbutton.button } as i32
{
move_right(&mut selected);
} else if let Some(ui::config::InputItem::JoystickButton(
joystick_button,
)) = &profile.inputs[B_BUTTON][0]
&& joystick_button.id == unsafe { event.jbutton.button } as i32
{
delete_binding(selected, profile);
} else if let Some(ui::config::InputItem::JoystickButton(
joystick_button,
)) = &profile.inputs[A_BUTTON][0]
&& joystick_button.id == unsafe { event.jbutton.button } as i32
&& select_or_save(selected, &mut gather, &mut gather_timer)
{
return true;
}
} else {
profile.inputs[selected.0][selected.1] = Some(
ui::config::InputItem::JoystickButton(ui::config::InputKeyButton {
id: i32::from(unsafe { event.jbutton.button }),
}),
);
(gather, gather_timer) =
advance_cursor(&mut selected, &mut auto_advance);
}
}
}
sdl3_sys::events::SDL_EVENT_JOYSTICK_HAT_MOTION => {
let state = unsafe { event.jhat.value };
let hat = unsafe { event.jhat.hat };
if dinput {
if gather == 0 {
if let Some(ui::config::InputItem::JoystickHat(joystick_hat)) =
&profile.inputs[D_DPAD][0]
&& joystick_hat.id == hat as i32
&& joystick_hat.direction == state
{
move_down(&mut selected);
} else if let Some(ui::config::InputItem::JoystickHat(joystick_hat)) =
&profile.inputs[U_DPAD][0]
&& joystick_hat.id == hat as i32
&& joystick_hat.direction == state
{
move_up(&mut selected);
} else if let Some(ui::config::InputItem::JoystickHat(joystick_hat)) =
&profile.inputs[L_DPAD][0]
&& joystick_hat.id == hat as i32
&& joystick_hat.direction == state
{
move_left(&mut selected);
} else if let Some(ui::config::InputItem::JoystickHat(joystick_hat)) =
&profile.inputs[R_DPAD][0]
&& joystick_hat.id == hat as i32
&& joystick_hat.direction == state
{
move_right(&mut selected);
} else if let Some(ui::config::InputItem::JoystickHat(joystick_hat)) =
&profile.inputs[B_BUTTON][0]
&& joystick_hat.id == hat as i32
&& joystick_hat.direction == state
{
delete_binding(selected, profile);
} else if let Some(ui::config::InputItem::JoystickHat(joystick_hat)) =
&profile.inputs[A_BUTTON][0]
&& joystick_hat.id == hat as i32
&& joystick_hat.direction == state
&& select_or_save(selected, &mut gather, &mut gather_timer)
{
return true;
}
} else if state != sdl3_sys::joystick::SDL_HAT_CENTERED {
profile.inputs[selected.0][selected.1] = Some(
ui::config::InputItem::JoystickHat(ui::config::InputJoystickHat {
id: hat as i32,
direction: state,
}),
);
(gather, gather_timer) =
advance_cursor(&mut selected, &mut auto_advance);
}
}
}
sdl3_sys::events::SDL_EVENT_JOYSTICK_AXIS_MOTION => {
let axis_value = unsafe { event.jaxis }.value;
let axis = unsafe { event.jaxis }.axis;
let mut initial_state = 0;
let has_initial_state = unsafe {
sdl3_sys::joystick::SDL_GetJoystickAxisInitialState(
sdl3_sys::joystick::SDL_GetJoystickFromID(event.jaxis.which),
axis as i32,
&mut initial_state,
)
};
initial_state = if has_initial_state {
if initial_state < i16::MIN / 2 {
i16::MIN
} else if initial_state > i16::MAX / 2 {
i16::MAX
} else {
0
}
} else {
0
};
if dinput && gather != 0 && axis_value.abs_diff(initial_state) > (u16::MAX / 4)
{
profile.inputs[selected.0][selected.1] = Some(
ui::config::InputItem::JoystickAxis(ui::config::InputControllerAxis {
id: i32::from(axis),
axis: axis_value.signum(),
initial_state,
}),
);
(gather, gather_timer) = advance_cursor(&mut selected, &mut auto_advance);
}
}
_ => (),
}
}
unsafe {
sdl3_sys::everything::SDL_RenderClear(renderer);
let ttf_text =
sdl3_ttf_sys::ttf::TTF_CreateText(text_engine, font, std::ptr::null(), 0);
render_screen(window, renderer, ttf_text, font, profile, selected, gather);
sdl3_ttf_sys::ttf::TTF_DestroyText(ttf_text);
sdl3_sys::render::SDL_RenderPresent(renderer);
}
}
false
}
fn move_left(selected: &mut (usize, usize)) {
selected.1 = selected.1.saturating_sub(1)
}
fn move_right(selected: &mut (usize, usize)) {
selected.1 = selected.1.saturating_add(1).min(1)
}
fn move_up(selected: &mut (usize, usize)) {
selected.0 = selected.0.saturating_sub(1)
}
fn move_down(selected: &mut (usize, usize)) {
selected.0 = selected.0.saturating_add(1).min(PROFILE_SIZE)
}
fn delete_binding(selected: (usize, usize), profile: &mut ui::config::InputProfile) {
if selected.0 < PROFILE_SIZE {
profile.inputs[selected.0][selected.1] = None;
}
}
fn select_or_save(
selected: (usize, usize),
gather: &mut usize,
gather_timer: &mut Option<std::time::Instant>,
) -> bool {
if selected.0 == PROFILE_SIZE {
return true;
} else {
*gather = GATHER_TIME;
*gather_timer = Some(std::time::Instant::now());
}
false
}
fn render_screen(
window: *mut sdl3_sys::video::SDL_Window,
renderer: *mut sdl3_sys::render::SDL_Renderer,
ttf_text: *mut sdl3_ttf_sys::ttf::TTF_Text,
font: *mut sdl3_ttf_sys::ttf::TTF_Font,
profile: &ui::config::InputProfile,
selected: (usize, usize),
gather: usize,
) {
let mut rect: sdl3_sys::rect::SDL_Rect = Default::default();
unsafe { sdl3_sys::video::SDL_GetWindowSafeArea(window, &mut rect) };
let row_height = unsafe { sdl3_ttf_sys::ttf::TTF_GetFontLineSkip(font) } as usize;
let key_labels: [&str; PROFILE_SIZE] = [
"D Right",
"D Left",
"D Down",
"D Up",
"Start",
"Z",
"B",
"A",
"C Right",
"C Left",
"C Down",
"C Up",
"R",
"L",
"Control Stick Right",
"Control Stick Left",
"Control Stick Down",
"Control Stick Up",
"Hotkey Activator",
];
// headers
unsafe {
sdl3_ttf_sys::ttf::TTF_SetFontStyle(
font,
sdl3_ttf_sys::ttf::TTF_STYLE_BOLD | sdl3_ttf_sys::ttf::TTF_STYLE_UNDERLINE,
);
let c_text = std::ffi::CString::new("Inputs").unwrap();
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, c_text.as_ptr(), 0);
sdl3_ttf_sys::ttf::TTF_DrawRendererText(ttf_text, rect.x as f32, rect.y as f32);
let c_text = std::ffi::CString::new("Binding 1").unwrap();
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, c_text.as_ptr(), 0);
sdl3_ttf_sys::ttf::TTF_DrawRendererText(
ttf_text,
rect.x as f32 + (rect.w / 3) as f32 * 1.0,
rect.y as f32,
);
let c_text = std::ffi::CString::new("Binding 2").unwrap();
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, c_text.as_ptr(), 0);
sdl3_ttf_sys::ttf::TTF_DrawRendererText(
ttf_text,
rect.x as f32 + (rect.w / 3) as f32 * 2.0,
rect.y as f32,
);
sdl3_ttf_sys::ttf::TTF_SetFontStyle(font, sdl3_ttf_sys::ttf::TTF_STYLE_NORMAL);
}
for (i, label) in key_labels.iter().enumerate() {
let c_text = std::ffi::CString::new(*label).unwrap();
unsafe {
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, c_text.as_ptr(), 0);
sdl3_ttf_sys::ttf::TTF_DrawRendererText(
ttf_text,
rect.x as f32,
rect.y as f32 + ((i + 1) * row_height) as f32,
);
let binding_1 =
std::ffi::CString::new(get_binding_text(&profile.inputs[i][0])).unwrap();
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, binding_1.as_ptr(), 0);
draw_binding_text(renderer, ttf_text, rect, row_height, selected, gather, i, 0);
let binding_2 =
std::ffi::CString::new(get_binding_text(&profile.inputs[i][1])).unwrap();
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, binding_2.as_ptr(), 0);
draw_binding_text(renderer, ttf_text, rect, row_height, selected, gather, i, 1);
}
}
let c_text = std::ffi::CString::new("Save and Exit").unwrap();
unsafe {
sdl3_ttf_sys::ttf::TTF_SetFontStyle(font, sdl3_ttf_sys::ttf::TTF_STYLE_BOLD);
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, c_text.as_ptr(), 0);
let (mut text_w, mut text_h) = (0, 0);
sdl3_ttf_sys::ttf::TTF_GetTextSize(ttf_text, &mut text_w, &mut text_h);
if selected.0 == PROFILE_SIZE {
draw_highlight(
renderer,
rect.x as f32 + (rect.w - text_w) as f32 / 2.0,
rect.y as f32 + ((PROFILE_SIZE + 1) * row_height) as f32,
text_w,
text_h,
);
}
sdl3_ttf_sys::ttf::TTF_DrawRendererText(
ttf_text,
rect.x as f32 + (rect.w - text_w) as f32 / 2.0,
rect.y as f32 + ((PROFILE_SIZE + 1) * row_height) as f32,
);
};
}
fn draw_highlight(
renderer: *mut sdl3_sys::render::SDL_Renderer,
x: f32,
y: f32,
text_w: i32,
text_h: i32,
) {
unsafe {
sdl3_sys::render::SDL_SetRenderDrawColor(renderer, 50, 100, 180, 255);
let highlight = sdl3_sys::rect::SDL_FRect {
x,
y,
w: text_w as f32,
h: text_h as f32,
};
sdl3_sys::render::SDL_RenderFillRect(renderer, &highlight);
sdl3_sys::render::SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
}
}
#[allow(clippy::too_many_arguments)]
fn draw_binding_text(
renderer: *mut sdl3_sys::render::SDL_Renderer,
ttf_text: *mut sdl3_ttf_sys::ttf::TTF_Text,
rect: sdl3_sys::rect::SDL_Rect,
row_height: usize,
selected: (usize, usize),
gather: usize,
i: usize,
binding: usize,
) {
unsafe {
if selected.0 == i && selected.1 == binding {
if gather > 0 {
let gather_text = std::ffi::CString::new(format!("{}...", gather)).unwrap();
sdl3_ttf_sys::ttf::TTF_SetTextString(ttf_text, gather_text.as_ptr(), 0);
}
let (mut text_w, mut text_h) = (0, 0);
sdl3_ttf_sys::ttf::TTF_GetTextSize(ttf_text, &mut text_w, &mut text_h);
draw_highlight(
renderer,
rect.x as f32 + (rect.w / 3) as f32 * if selected.1 == 0 { 1.0 } else { 2.0 },
rect.y as f32 + ((i + 1) * row_height) as f32,
text_w,
text_h,
);
}
sdl3_ttf_sys::ttf::TTF_DrawRendererText(
ttf_text,
rect.x as f32 + (rect.w / 3) as f32 * (binding as f32 + 1.0),
rect.y as f32 + ((i + 1) * row_height) as f32,
);
}
}
fn get_binding_text(binding: &Option<ui::config::InputItem>) -> String {
if let Some(binding) = binding {
match binding {
ui::config::InputItem::Key(key) => {
return unsafe {
std::ffi::CStr::from_ptr(sdl3_sys::keyboard::SDL_GetScancodeName(
sdl3_sys::scancode::SDL_Scancode(key.id),
))
.to_str()
.unwrap()
.to_string()
};
}
ui::config::InputItem::ControllerButton(controller_button) => {
return unsafe {
std::ffi::CStr::from_ptr(sdl3_sys::gamepad::SDL_GetGamepadStringForButton(
sdl3_sys::gamepad::SDL_GamepadButton(controller_button.id),
))
.to_str()
.unwrap()
.to_string()
};
}
ui::config::InputItem::ControllerAxis(controller_axis) => {
return unsafe {
let axis =
std::ffi::CStr::from_ptr(sdl3_sys::gamepad::SDL_GetGamepadStringForAxis(
sdl3_sys::gamepad::SDL_GamepadAxis(controller_axis.id),
))
.to_str()
.unwrap()
.to_string();
let direction = if controller_axis.axis > 0 { "+" } else { "-" };
format!("{} {}", axis, direction)
};
}
ui::config::InputItem::JoystickButton(joystick_button) => {
return format!("Joystick Button {}", joystick_button.id);
}
ui::config::InputItem::JoystickHat(joystick_hat) => {
let direction = match joystick_hat.direction {
1 => "Up",
2 => "Right",
4 => "Down",
8 => "Left",
_ => "Unknown",
};
return format!("Joystick Hat {} {}", joystick_hat.id, direction);
}
ui::config::InputItem::JoystickAxis(joystick_axis) => {
let direction = if joystick_axis.axis > 0 { "+" } else { "-" };
return format!("Joystick Axis {} {}", joystick_axis.id, direction);
}
}
}
"(unset)".to_string()
}
pub fn get_default_profile() -> ui::config::InputProfile {
let mut inputs: [[Option<ui::config::InputItem>; 2]; PROFILE_SIZE] =
[const { [None, None] }; PROFILE_SIZE];
inputs[R_DPAD] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_D),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_RIGHT),
},
)),
];
inputs[L_DPAD] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_A),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_LEFT),
},
)),
];
inputs[D_DPAD] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_S),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_DOWN),
},
)),
];
inputs[U_DPAD] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_W),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_DPAD_UP),
},
)),
];
inputs[START_BUTTON] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_RETURN),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_START),
},
)),
];
inputs[Z_TRIG] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_Z),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_LEFT_TRIGGER),
axis: 1,
initial_state: 0,
},
)),
];
inputs[B_BUTTON] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_LCTRL),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_WEST),
},
)),
];
inputs[A_BUTTON] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_LSHIFT),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_SOUTH),
},
)),
];
inputs[R_CBUTTON] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_L),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_RIGHTX),
axis: 1,
initial_state: 0,
},
)),
];
inputs[L_CBUTTON] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_J),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_RIGHTX),
axis: -1,
initial_state: 0,
},
)),
];
inputs[D_CBUTTON] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_K),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_RIGHTY),
axis: 1,
initial_state: 0,
},
)),
];
inputs[U_CBUTTON] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_I),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_RIGHTY),
axis: -1,
initial_state: 0,
},
)),
];
inputs[R_TRIG] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_C),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER),
},
)),
];
inputs[L_TRIG] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_X),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_LEFT_SHOULDER),
},
)),
];
inputs[AXIS_LEFT] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_LEFT),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_LEFTX),
axis: -1,
initial_state: 0,
},
)),
];
inputs[AXIS_RIGHT] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_RIGHT),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_LEFTX),
axis: 1,
initial_state: 0,
},
)),
];
inputs[AXIS_UP] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_UP),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_LEFTY),
axis: -1,
initial_state: 0,
},
)),
];
inputs[AXIS_DOWN] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_DOWN),
})),
Some(ui::config::InputItem::ControllerAxis(
ui::config::InputControllerAxis {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_AXIS_LEFTY),
axis: 1,
initial_state: 0,
},
)),
];
inputs[HOTKEY] = [
Some(ui::config::InputItem::Key(ui::config::InputKeyButton {
id: i32::from(sdl3_sys::scancode::SDL_SCANCODE_COMMA),
})),
Some(ui::config::InputItem::ControllerButton(
ui::config::InputKeyButton {
id: i32::from(sdl3_sys::gamepad::SDL_GAMEPAD_BUTTON_BACK),
},
)),
];
ui::config::InputProfile {
inputs,
dinput: false,
deadzone: DEADZONE_DEFAULT,
}
}
+14 -4
View File
@@ -65,13 +65,17 @@ struct NetplayPingMessage {
num_of_peers: usize,
}
fn select_rom(weak: slint::Weak<AppWindow>, rom_dir: slint::SharedString) {
fn select_rom(
weak: slint::Weak<AppWindow>,
rom_dir: slint::SharedString,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let select_rom = ui::gui::select_rom(rom_dir);
tokio::spawn(async move {
if let Some(file) = select_rom.await {
if let Some(rom_contents) = device::get_rom_contents(&file) {
let hash = device::cart::rom::calculate_hash(&rom_contents);
let mut game_name = ui::storage::get_game_name(&rom_contents);
let mut game_name = ui::gui::get_nointro_name(&rom_contents, no_intro_map).await;
let pal = device::cart::rom::is_system_pal(&rom_contents);
let game_crc = ui::storage::get_game_crc(&rom_contents);
let cheats = ui::config::Cheats::new();
@@ -108,6 +112,7 @@ fn select_rom(weak: slint::Weak<AppWindow>, rom_dir: slint::SharedString) {
});
}
#[allow(clippy::too_many_arguments)]
fn setup_callbacks(
app: &AppWindow,
netplay_write_sender: &tokio::sync::broadcast::Sender<Option<NetplayLobbyMessage>>,
@@ -116,6 +121,7 @@ fn setup_callbacks(
netplay_write_receiver: &tokio::sync::broadcast::Receiver<Option<NetplayLobbyMessage>>,
close_ping_tx: &tokio::sync::broadcast::Sender<()>,
close_ping_rx: &tokio::sync::broadcast::Receiver<()>,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let weak = app.as_weak();
let netplay_write_sender_create_session = netplay_write_sender.clone();
@@ -238,7 +244,7 @@ fn setup_callbacks(
let weak_app = app.as_weak();
app.on_netplay_select_rom(move |rom_dir| {
select_rom(weak_app.clone(), rom_dir);
select_rom(weak_app.clone(), rom_dir, no_intro_map.clone());
});
let weak_app = app.as_weak();
@@ -992,7 +998,10 @@ fn setup_join_window(
app.invoke_netplay_refresh_sessions();
}
pub fn netplay_window(app: &AppWindow) {
pub fn netplay_window(
app: &AppWindow,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let (netplay_read_sender, netplay_read_receiver): (
tokio::sync::broadcast::Sender<Option<NetplayLobbyMessage>>,
tokio::sync::broadcast::Receiver<Option<NetplayLobbyMessage>>,
@@ -1016,5 +1025,6 @@ pub fn netplay_window(app: &AppWindow) {
&netplay_write_receiver,
&close_ping_tx,
&close_ping_rx,
no_intro_map,
);
}
+1 -1
View File
@@ -20,7 +20,7 @@ pub fn ra_window(app: &ui::gui::AppWindow) {
}
if !cfg!(ra_hardcore_enabled) {
app.set_ra_softcore_only(true);
app.set_ra_casual_only(true);
}
if app.get_ra_enabled() && !app.get_ra_username().is_empty() {
+4 -40
View File
@@ -20,8 +20,8 @@ fn build_gfx_info(device: &mut device::Device, netplay: bool) -> GFX_INFO {
DPC_END_REG: &mut device.rdp.regs_dpc[device::rdp::DPC_END_REG],
DPC_STATUS_REG: &mut device.rdp.regs_dpc[device::rdp::DPC_STATUS_REG],
PAL: device.cart.pal,
widescreen: device.ui.config.video.widescreen,
fullscreen: device.ui.video.fullscreen,
widescreen: device.ui.video.widescreen,
vsync: if !netplay {
device.ui.config.video.vsync
} else {
@@ -56,14 +56,14 @@ pub fn init(device: &mut device::Device, netplay: bool) {
2
};
if device.cart.pal {
window_width = if device.ui.config.video.widescreen {
window_width = if device.ui.video.widescreen {
PAL_WIDESCREEN_WIDTH * scale
} else {
PAL_STANDARD_WIDTH * scale
};
window_height = PAL_HEIGHT * scale;
} else {
window_width = if device.ui.config.video.widescreen {
window_width = if device.ui.video.widescreen {
NTSC_WIDESCREEN_WIDTH * scale
} else {
NTSC_STANDARD_WIDTH * scale
@@ -182,16 +182,14 @@ pub fn load_state(device: &mut device::Device, rdp_state: *const u8) {
pub fn pause_loop(ui: &mut ui::Ui, frame_time: f64) {
let mut paused = true;
let mut frame_advance = false;
let mut pause_counter = 0;
while paused && !frame_advance {
std::thread::sleep(std::time::Duration::from_secs_f64(frame_time));
ui::input::get(ui, 0, pause_counter); // to gather hotkey input
unsafe { sdl3_sys::events::SDL_PumpEvents() };
ui::input::get(ui, 0); // to gather hotkey input
retroachievements::do_idle();
let callback = unsafe { rdp_check_callback() };
paused = callback.paused;
frame_advance = callback.frame_advance;
pause_counter += 1;
}
}
@@ -276,37 +274,3 @@ pub fn onscreen_message(message: &str, milliseconds: MESSAGE_LENGTH) {
rdp_onscreen_message(c_message.as_ptr(), milliseconds)
};
}
pub fn draw_text(
text: &str,
renderer: *mut sdl3_sys::render::SDL_Renderer,
image_texture: *mut sdl3_sys::render::SDL_Texture,
text_engine: *mut sdl3_ttf_sys::ttf::TTF_TextEngine,
font: *mut sdl3_ttf_sys::ttf::TTF_Font,
) {
unsafe {
let (mut w, mut h) = (0, 0);
sdl3_sys::render::SDL_GetRenderOutputSize(renderer, &mut w, &mut h);
let c_text = std::ffi::CString::new(text).unwrap();
let ttf_text = sdl3_ttf_sys::ttf::TTF_CreateText(text_engine, font, c_text.as_ptr(), 0);
sdl3_sys::everything::SDL_RenderClear(renderer);
let rect = sdl3_sys::rect::SDL_FRect {
x: 0.0,
y: 0.0,
w: w as f32,
h: (h - sdl3_ttf_sys::ttf::TTF_GetFontHeight(font)) as f32,
};
sdl3_sys::render::SDL_RenderTexture(renderer, image_texture, std::ptr::null(), &rect);
let (mut text_w, mut text_h) = (0, 0);
sdl3_ttf_sys::ttf::TTF_GetTextSize(ttf_text, &mut text_w, &mut text_h);
sdl3_ttf_sys::ttf::TTF_DrawRendererText(
ttf_text,
(w / 2 - text_w / 2) as f32,
(h - text_h) as f32,
);
sdl3_sys::render::SDL_RenderPresent(renderer);
sdl3_ttf_sys::ttf::TTF_DestroyText(ttf_text);
}
}