diff --git a/.github/workflows/Hydra_Build.yml b/.github/workflows/Hydra_Build.yml index 785e0e4a2..6827fffe7 100644 --- a/.github/workflows/Hydra_Build.yml +++ b/.github/workflows/Hydra_Build.yml @@ -70,7 +70,7 @@ jobs: vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON -DBUILD_HYDRA_CORE=ON + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON -DBUILD_HYDRA_CORE=ON -DCMAKE_OSX_ARCHITECTURE=x86_64 - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} @@ -84,7 +84,7 @@ jobs: - name: Configure CMake (Again) run: | rm -rf ${{github.workspace}}/build - cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON -DBUILD_LIBRETRO_CORE=ON + cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON -DBUILD_LIBRETRO_CORE=ON -DCMAKE_OSX_ARCHITECTURE=x86_64 - name: Build (Again) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} && ls -R ${{github.workspace}}/build diff --git a/.github/workflows/MacOS_Build.yml b/.github/workflows/MacOS_Build.yml index 76b75bd4b..a0c09bbfe 100644 --- a/.github/workflows/MacOS_Build.yml +++ b/.github/workflows/MacOS_Build.yml @@ -12,10 +12,11 @@ env: jobs: build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + strategy: + matrix: + arch: [x86_64, arm64] + + name: MacOS-${{ matrix.arch }} runs-on: macos-13 steps: @@ -33,7 +34,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON -DCMAKE_OSX_ARCHITECTURES=${{ matrix.arch }} - name: Build # Build your program with the given configuration @@ -49,10 +50,45 @@ jobs: run: codesign --force -s - -vvvv Alber.app - name: Zip it up - run: zip -r Alber Alber.app + run: zip -r Alber-${{ matrix.arch }} Alber.app - name: Upload MacOS App uses: actions/upload-artifact@v4 with: - name: MacOS Alber App Bundle - path: 'Alber.zip' + name: MacOS Alber App Bundle (${{ matrix.arch }}) + path: Alber-${{ matrix.arch }}.zip + + MacOS-Universal: + name: MacOS-Universal + needs: [build] + runs-on: macos-13 + + steps: + - name: Download x86_64 + uses: actions/download-artifact@v4 + with: + name: MacOS Alber App Bundle (x86_64) + path: x86_64 + - name: Download ARM64 + uses: actions/download-artifact@v4 + with: + name: MacOS Alber App Bundle (arm64) + path: arm64 + - name: Combine app bundles + shell: bash + run: | + set -x + unzip x86_64/*.zip -d x86_64 + unzip arm64/*.zip -d arm64 + lipo {x86_64,arm64}/Alber.app/Contents/MacOS/Alber -create -output Alber + cp -v -a arm64/Alber.app Alber.app + cp -v Alber Alber.app/Contents/MacOS/Alber + # Mix in x86_64 files that do not appear in the ARM64 build (e.g. libvulkan) + cp -v -R -n x86_64/Alber.app/* Alber.app/ || true + codesign --force -s - -vvvv Alber.app + zip -r -y Alber-universal.zip Alber.app + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: MacOS Alber App Bundle (universal) + path: Alber-universal.zip diff --git a/.github/workflows/Qt_Build.yml b/.github/workflows/Qt_Build.yml index 3b846a275..ebd856c6a 100644 --- a/.github/workflows/Qt_Build.yml +++ b/.github/workflows/Qt_Build.yml @@ -51,6 +51,11 @@ jobs: path: upload MacOS: + strategy: + matrix: + arch: [x86_64, arm64] + + name: MacOS-${{ matrix.arch }} runs-on: macos-13 steps: @@ -69,11 +74,17 @@ jobs: run: | brew install dylibbundler imagemagick - - name: Install qt - run: brew install qt && which macdeployqt + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + aqtversion: '==3.1.*' + version: '6.8.1' + host: 'mac' + target: 'desktop' + arch: 'clang_64' - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON -DENABLE_QT_GUI=ON + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON -DENABLE_QT_GUI=ON -DCMAKE_OSX_ARCHITECTURES=${{ matrix.arch }} - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} @@ -87,13 +98,48 @@ jobs: run: codesign --force -s - -vvvv Alber.app - name: Zip it up - run: zip -r Alber Alber.app + run: zip -r Alber-${{ matrix.arch }} Alber.app - name: Upload MacOS App uses: actions/upload-artifact@v4 with: - name: MacOS Alber App Bundle - path: 'Alber.zip' + name: MacOS Alber App Bundle (${{ matrix.arch }}) + path: Alber-${{ matrix.arch }}.zip + + MacOS-Universal: + name: MacOS-Universal + needs: [MacOS] + runs-on: macos-13 + + steps: + - name: Download x86_64 + uses: actions/download-artifact@v4 + with: + name: MacOS Alber App Bundle (x86_64) + path: x86_64 + - name: Download ARM64 + uses: actions/download-artifact@v4 + with: + name: MacOS Alber App Bundle (arm64) + path: arm64 + - name: Combine app bundles + shell: bash + run: | + set -x + unzip x86_64/*.zip -d x86_64 + unzip arm64/*.zip -d arm64 + lipo {x86_64,arm64}/Alber.app/Contents/MacOS/Alber -create -output Alber + cp -v -a arm64/Alber.app Alber.app + cp -v Alber Alber.app/Contents/MacOS/Alber + # Mix in x86_64 files that do not appear in the ARM64 build (e.g. libvulkan) + cp -v -R -n x86_64/Alber.app/* Alber.app/ || true + codesign --force -s - -vvvv Alber.app + zip -r -y Alber-universal.zip Alber.app + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: MacOS Alber App Bundle (universal) + path: Alber-universal.zip Linux: runs-on: ubuntu-24.04 @@ -107,7 +153,7 @@ jobs: run: | sudo apt-get update && sudo apt install libx11-dev libgl1 libglx-mesa0 mesa-common-dev libfuse2 libwayland-dev libgl1-mesa-dev sudo apt update - sudo apt install qt6-base-dev qt6-base-private-dev + sudo apt install qt6-base-dev qt6-base-private-dev qt6-tools-dev - name: Install newer Clang run: | diff --git a/.gitmodules b/.gitmodules index b1e054237..9fcd8d60a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,9 +40,6 @@ [submodule "third_party/zep"] path = third_party/zep url = https://github.com/Panda3DS-emu/zep -[submodule "third_party/oaknut"] - path = third_party/oaknut - url = https://github.com/merryhime/oaknut [submodule "third_party/luv"] path = third_party/luv url = https://github.com/luvit/luv @@ -85,3 +82,6 @@ [submodule "third_party/cryptoppwin"] path = third_party/cryptoppwin url = https://github.com/shadps4-emu/ext-cryptoppwin +[submodule "third_party/oaknut"] + path = third_party/oaknut + url = https://github.com/panda3ds-emu/oaknut diff --git a/CMakeLists.txt b/CMakeLists.txt index 16ad1c411..8df42ff95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,26 +219,51 @@ if(ENABLE_LUAJIT) target_link_libraries(AlberCore PRIVATE libluajit) endif() -# Check for x64 -if (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86-64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") +# Detect target architecture +if (NOT APPLE OR "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") + # Normal target detection + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86-64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") set(HOST_X64 TRUE) + else() + set(HOST_X64 FALSE) + endif() + + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(HOST_ARM64 TRUE) + else() + set(HOST_ARM64 FALSE) + endif() +else() + # Apple target detection + if("x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(HOST_X64 TRUE) + else() + set(HOST_X64 FALSE) + endif() + + if("arm64" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(HOST_ARM64 TRUE) + else() + set(HOST_ARM64 FALSE) + endif() + + if (HOST_ARM64 AND HOST_X64) + message(FATAL_ERROR "Universal builds not supported like this! Please compile separately and stitch together") + endif() +endif() + +if (HOST_X64) add_subdirectory(third_party/xbyak) # Add xbyak submodule for x86 JITs include_directories(third_party/xbyak) add_compile_definitions(PANDA3DS_DYNAPICA_SUPPORTED) add_compile_definitions(PANDA3DS_X64_HOST) -else() - set(HOST_X64 FALSE) endif() -# Check for arm64 -if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - set(HOST_ARM64 TRUE) +if (HOST_ARM64) add_subdirectory(third_party/oaknut) # Add Oaknut submodule for arm64 JITs include_directories(third_party/oaknut/include) add_compile_definitions(PANDA3DS_DYNAPICA_SUPPORTED) add_compile_definitions(PANDA3DS_ARM64_HOST) -else() - set(HOST_ARM64 FALSE) endif() # Enable SSE4.1 if it's not explicitly disabled @@ -315,6 +340,7 @@ set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/cor set(FS_SOURCE_FILES src/core/fs/archive_self_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp src/core/fs/archive_ext_save_data.cpp src/core/fs/archive_ncch.cpp src/core/fs/romfs.cpp src/core/fs/ivfc.cpp src/core/fs/archive_user_save_data.cpp src/core/fs/archive_system_save_data.cpp + src/core/fs/archive_twl_photo.cpp src/core/fs/archive_twl_sound.cpp src/core/fs/archive_card_spi.cpp ) set(APPLET_SOURCE_FILES src/core/applets/applet.cpp src/core/applets/mii_selector.cpp src/core/applets/software_keyboard.cpp src/core/applets/applet_manager.cpp @@ -364,8 +390,8 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/PICA/pica_vert_config.hpp include/sdl_sensors.hpp include/PICA/draw_acceleration.hpp include/renderdoc.hpp include/align.hpp include/audio/aac_decoder.hpp include/PICA/pica_simd.hpp include/services/fonts.hpp include/audio/audio_interpolation.hpp include/audio/hle_mixer.hpp include/audio/dsp_simd.hpp - include/enum_flag_ops.hpp include/services/dsp_firmware_db.hpp include/frontend_settings.hpp - include/dynamic_library.hpp + include/services/dsp_firmware_db.hpp include/frontend_settings.hpp include/fs/archive_twl_photo.hpp + include/fs/archive_twl_sound.hpp include/fs/archive_card_spi.hpp include/enum_flag_ops.hpp include/dynamic_library.hpp ) cmrc_add_resource_library( @@ -647,7 +673,7 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE) add_executable(Alber) if(ENABLE_QT_GUI) - find_package(Qt6 REQUIRED COMPONENTS Widgets) + find_package(Qt6 REQUIRED COMPONENTS Widgets LinguistTools) if(NOT ENABLE_OPENGL) message(FATAL_ERROR "Qt frontend requires OpenGL") endif() @@ -657,7 +683,7 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE) set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp src/panda_qt/config_window.cpp src/panda_qt/zep.cpp src/panda_qt/text_editor.cpp src/panda_qt/cheats_window.cpp src/panda_qt/mappings.cpp - src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp src/panda_qt/shader_editor.cpp + src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp src/panda_qt/shader_editor.cpp src/panda_qt/translations.cpp ) set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp include/panda_qt/config_window.hpp include/panda_qt/text_editor.hpp include/panda_qt/cheats_window.hpp @@ -710,6 +736,23 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE) docs/img/sparkling_icon.png docs/img/battery_icon.png docs/img/sdcard_icon.png docs/img/rnap_icon.png docs/img/rcow_icon.png docs/img/skyemu_icon.png ) + + # Translation files in Qt's .ts format. Will be converted into binary files and embedded into the executable + set(TRANSLATIONS_TS docs/translations/en.ts docs/translations/el.ts docs/translations/es.ts docs/translations/pt_br.ts docs/translations/nl.ts) + set_source_files_properties(${TRANSLATIONS_TS} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations") + qt_add_translation(TRANSLATIONS_QM ${TRANSLATIONS_TS}) + + set(TRANSLATIONS_QRC ${CMAKE_CURRENT_BINARY_DIR}/translations/translations.qrc) + file(WRITE ${TRANSLATIONS_QRC} "\n") + foreach (QM ${TRANSLATIONS_QM}) + message("${QM}") + get_filename_component(QM_FILE ${QM} NAME) + file(APPEND ${TRANSLATIONS_QRC} "${QM_FILE}\n") + endforeach (QM) + file(APPEND ${TRANSLATIONS_QRC} "") + + qt_add_resources(TRANSLATIONS ${TRANSLATIONS_QRC}) + set(APP_RESOURCES ${APP_RESOURCES} ${TRANSLATIONS}) else() set(FRONTEND_SOURCE_FILES src/panda_sdl/main.cpp src/panda_sdl/frontend_sdl.cpp src/panda_sdl/mappings.cpp) set(FRONTEND_HEADER_FILES "include/panda_sdl/frontend_sdl.hpp") diff --git a/docs/translations/el.ts b/docs/translations/el.ts new file mode 100644 index 000000000..0368d8bda --- /dev/null +++ b/docs/translations/el.ts @@ -0,0 +1,763 @@ + + + AboutWindow + + + About Panda3DS + Σχετικά με το Panda3DS + + + + Panda3DS is a free and open source Nintendo 3DS emulator, for Windows, MacOS and Linux + Τo Panda3DS είναι ένας δωρεάν και open source εξομοιωτής του Nintendo 3DS, για Windows, MacOS και Linux + + + + Visit panda3ds.com for help with Panda3DS and links to our official support sites. + Επισκεφτείται το panda3ds.com για βοήθεια με το Panda3DS και συνδέσμους στις επίσημες σελίδες υποστήριξης μας. + + + + Panda3DS is developed by volunteers in their spare time. Below is a list of some of these volunteers who've agreed to be listed here, in no particular order.<br>If you think you should be listed here too, please inform us<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + + + + + CheatEditDialog + + + Edit Cheat + Επεξεργασία Κωδικού + + + + Cheat name + Όνομα κωδικού + + + + CheatEntryWidget + + + Edit + Επεξεργασία + + + + CheatsWindow + + + Cheats + Κωδικοί + + + + Add + Προσθήκη + + + + Remove + Αφαίρεση + + + + ConfigWindow + + + Configuration + Ρυθμίσεις + + + + Interface Settings + Ρυθμίσεις Διεπαφής + + + + System + Σύστημα + + + + Light + Φωτεινό + + + + Dark + Σκοτεινό + + + + Greetings Cat + Γεια Σου Γάτα + + + + Cream + Κρέμα + + + + Color theme + Χρώματα + + + + Happy panda + Χαρούμενο Πάντα + + + + Happy panda (colourful) + Χαρούμενο Πάντα (χρωματιστό) + + + + Sleepy panda + Πάντα που νυστάζει + + + + Cow panda + Αγελάδα πάντα + + + + The penguin from SkyEmu + Ο πιγκουίνος από το SkyEmu + + + + Window icon + Εικονίδιο Παραθύρου + + + + Language + Γλώσσα + + + + Show version on window title + Εμφάνιση έκδοσης στον τίτλο του παραθύρου + + + + Alber v%1 + Αλβέρτος v%1 + + + + Alber + Αλβέρτος + + + + Remember window position + Αποθήκευση θέσης παραθύρου + + + + General Settings + Γενικές Ρυθμίσεις + + + + Browse... + Περιήγηση + + + + Select Directory + Επιλογή φακέλου + + + + Default ROMs path + Προεπιλεγμένος φάκελος ROM + + + + Enable Discord RPC + Ενεργοποίηση Discord RPC + + + + Use portable build + Ενεργοποίηση φορητής εγκατάστασης + + + + Print version in console output + Εκτύπωση έκδοσης στην κονσόλα + + + + Graphics Settings + Ρυθμίσεις Γραφικών + + + + + Null + Κανένα + + + + OpenGL + + + + + Vulkan + + + + + GPU renderer + Πυρήνας GPU + + + + Enable Renderdoc + Ενεργοποίηση Renderdoc + + + + Enable shader JIT + Ενεργοποίηση μεταγλωττιστή shaders + + + + Enable VSync + Ενεργοποίηση VSync + + + + Use ubershaders (No stutter, maybe slower) + Χρήση ubershaders (Χωρίς stutter, ίσως πιο αργό) + + + + Accurate shader multiplication + Ακριβής πολλαπλασιασμός στα shaders + + + + Accelerate shaders + Επιτάχυνση shaders + + + + Force shadergen when rendering lights + Εξαναγκασμός shadergen όταν υπάρχουν φώτα + + + + Light threshold for forcing shadergen + Αριθμός φωτών για εξαναγκασμό shadergen + + + + Audio Settings + Ρυθμίσεις Ήχου + + + + LLE + + + + + HLE + + + + + DSP emulation + Εξομοίωση DSP + + + + Enable audio + Ενεργοποίηση ήχου + + + + Enable AAC audio + Ενεργοποίηση ήχου AAC + + + + Print DSP firmware + Εκτύπωση λογισμικού DSP + + + + Mute audio device + Σίγαση συσκευής ήχου + + + + Cubic + Κυβική + + + + Linear + Γραμμική + + + + Volume curve + Κλίμακα ήχου + + + + Audio device volume + Ένταση ήχου + + + + Battery Settings + Ρυθμίσεις μπαταρίας + + + + Battery percentage + Ποσοστό μπαταρίας + + + + Charger plugged + Φορτιστής + + + + SD Card Settings + Ρυθμίσης κάρτας SD + + + + Enable virtual SD card + Ενεργοποίηση εικονικής SD + + + + Write protect virtual SD card + Προστασία της SD από εγγραφή + + + + Interface + Διεπαφή + + + + User Interface settings + Ρυθμίσεις διεπαφής + + + + General + Γενικά + + + + General emulator settings + Γενικές ρυθμίσεις εξομοιωτή + + + + Graphics + Γραφικά + + + + Graphics emulation and output settings + Ρυθμίσεις εξομοίωσης γραφικών + + + + Audio + Ήχος + + + + Audio emulation and output settings + Ρυθμίσεις εξομοίωσης ήχου + + + + Battery + Μπαταρία + + + + Battery emulation settings + Ρυθμίσεις εξομοίωσης μπαταρίας + + + + SD Card + Κάρτα SD + + + + SD Card emulation settings + Ρυθμίσεις εξομοίωσης κάρτας SD + + + + Language change successful + Επιτυχία αλλαγής γλώσσας + + + + Restart Panda3DS for the new language to be used. + Επανεκκινήστε το Panda3DS για να εφαρμοστεί η νέα γλώσσα. + + + + Language change failed + Αποτυχία αλλαγής γλώσσας + + + + The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code... + Το Panda3DS δεν υποστηρίζει τον γλώσσα που επιλέξατε. Αν το βλέπετε αυτό, κάποιος έκανε λάθος στον κώδικα, κατηγορήστε τον Πάρη... + + + + MainWindow + + + Alber + Αλβέρτος + + + + File + Αρχεία + + + + Emulation + Εξομοίωση + + + + Tools + Εργαλεία + + + + About + Σχετικά + + + + Load game + Φόρτωση παιχνιδιού + + + + Load Lua script + Φόρτωση αρχείου Lua + + + + Open Panda3DS folder + Άνοιγμα φακέλου Panda3DS + + + + Pause + Παύση + + + + Resume + Συνέχεια + + + + Reset + Επανέναρξη + + + + Configure + Ρύθμιση + + + + Dump RomFS + + + + + Open Lua Editor + Άνοιγμα Lua Editor + + + + Open Cheats Editor + Άνοιγμα Editor κωδικών + + + + Open Patch Window + Άνοιγμα παραθύρου για patching + + + + Open Shader Editor + + + + + Dump loaded DSP firmware + + + + + About Panda3DS + Σχετικά με το Panda3DS + + + + Select 3DS ROM to load + Επιλέξτε 3DS ROM για να φορτώσετε + + + + Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + + + + + Select Lua script to load + Επιλέξτε αρχείο Lua για να φορτώσετε + + + + Lua scripts (*.lua *.txt) + + + + + Select folder to dump RomFS files to + + + + + Invalid format for RomFS dumping + + + + + The currently loaded app is not in a format that supports RomFS + + + + + + + OK + ΟΚ + + + + No RomFS found + Δεν βρέθηκε RomFS + + + + No RomFS partition was found in the loaded app + Δεν βρέθηκε RomFS στην εφαρμογή που έχει φορτωθεί + + + + Select file + Επιλέξτε αρχείο + + + + DSP firmware file (*.cdc) + + + + + No DSP firmware loaded + Δεν έχει φορτωθεί DSP firmware + + + + The currently loaded app has not uploaded a firmware to the DSP + + + + + Failed to open output file + Αποτυχία ανοίγματος του αρχείου εξόδου + + + + The currently loaded DSP firmware could not be written to the selected file. Please make sure you have permission to access this file + + + + + PatchWindow + + + ROM patcher + + + + + Select input file + Επιλογή αρχείου εισόδου + + + + + Select + Επιλέξτε + + + + + Select patch file + Επιλογή αρχείου patch + + + + Apply patch + Εφαρμογή patch + + + + Select file to patch + Επιλέξτε αρχείο να κάνετε patch + + + + + All files (*.*) + Όλα τα αρχεία (*.*) + + + + Patch files (*.ips *.ups *.bps) + + + + + Paths not provided correctly + + + + + Please provide paths for both the input file and the patch file + Παρακαλούμε διαλέξτε και αρχείο εισόδου και αρχείο patch + + + + Select file + Επιλογή αρχείου + + + + No output path + Δεν επιλέχθηκε φάκελος εξόδου + + + + No path was provided for the output file, no patching was done + Δεν επιλέχθηκε αρχείο εξόδου. Δεν έγινε patching + + + + Unknown patch format + Άγνωστο είδος patch + + + + Unknown format for patch file. Currently IPS, UPS and BPS are supported + Άγνωστο είδος αρχείου patch. Υποστηρίζονται αρχεία IPS, UPS και BPS + + + + Failed to open input files + Αποτυχία ανοίγματος των αρχείων εισόδου + + + + Make sure they're in a directory Panda3DS has access to + Βεβαιωθείτε ότι είναι σε φάκελο που έχει πρόσβαση το Panda3DS + + + + Patching Success + Επιτυχής Εφαρμογή Patch + + + + Your file was patched successfully. + To αρχείο σας έγινε patch με επιτυχία + + + + Checksum mismatch + + + + + Patch was applied successfully but a checksum mismatch was detected. The input or output files might not be correct + Το patch εφαρμόστηκε με επιτυχία αλλά ανιχνεύτηκε σφάλμα στο checksum. Ενδέχεται τα αρχεία εισόδου η εξόδου να είναι λανθασμένα + + + + Patching error + Σφάλμα στο patching + + + + An error occured while patching + Προέκυψε σφάλμα στο patching + + + + PatchWindow::PatchWindow + + + OK + ΟΚ + + + + ShaderEditorWindow + + + Reload shader + Επαναφόρτωση shader + + + + TextEditorWindow + + + Lua Editor + + + + + Load script + Φόρτωση αρχείου + + + \ No newline at end of file diff --git a/docs/translations/en.ts b/docs/translations/en.ts new file mode 100644 index 000000000..4a70fabb3 --- /dev/null +++ b/docs/translations/en.ts @@ -0,0 +1,766 @@ + + + + + AboutWindow + + + About Panda3DS + + + + + Panda3DS is a free and open source Nintendo 3DS emulator, for Windows, MacOS and Linux + + + + + Visit panda3ds.com for help with Panda3DS and links to our official support sites. + + + + + Panda3DS is developed by volunteers in their spare time. Below is a list of some of these volunteers who've agreed to be listed here, in no particular order.<br>If you think you should be listed here too, please inform us<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + + + + + CheatEditDialog + + + Edit Cheat + + + + + Cheat name + + + + + CheatEntryWidget + + + Edit + + + + + CheatsWindow + + + Cheats + + + + + Add + + + + + Remove + + + + + ConfigWindow + + + Configuration + + + + + Interface Settings + + + + + System + + + + + Light + + + + + Dark + + + + + Greetings Cat + + + + + Cream + + + + + Color theme + + + + + Happy panda + + + + + Happy panda (colourful) + + + + + Sleepy panda + + + + + Cow panda + + + + + The penguin from SkyEmu + + + + + Window icon + + + + + Language + + + + + Show version on window title + + + + + + Alber v%1 + + + + + Alber + + + + + Remember window position + + + + + General Settings + + + + + Browse... + + + + + Select Directory + + + + + Default ROMs path + + + + + Enable Discord RPC + + + + + Use portable build + + + + + Print version in console output + + + + + Graphics Settings + + + + + + Null + + + + + OpenGL + + + + + Vulkan + + + + + GPU renderer + + + + + Enable Renderdoc + + + + + Enable shader JIT + + + + + Enable VSync + + + + + Use ubershaders (No stutter, maybe slower) + + + + + Accurate shader multiplication + + + + + Accelerate shaders + + + + + Force shadergen when rendering lights + + + + + Light threshold for forcing shadergen + + + + + Audio Settings + + + + + LLE + + + + + HLE + + + + + DSP emulation + + + + + Enable audio + + + + + Enable AAC audio + + + + + Print DSP firmware + + + + + Mute audio device + + + + + Cubic + + + + + Linear + + + + + Volume curve + + + + + Audio device volume + + + + + Battery Settings + + + + + Battery percentage + + + + + Charger plugged + + + + + SD Card Settings + + + + + Enable virtual SD card + + + + + Write protect virtual SD card + + + + + Interface + + + + + User Interface settings + + + + + General + + + + + General emulator settings + + + + + Graphics + + + + + Graphics emulation and output settings + + + + + Audio + + + + + Audio emulation and output settings + + + + + Battery + + + + + Battery emulation settings + + + + + SD Card + + + + + SD Card emulation settings + + + + + Language change successful + + + + + Restart Panda3DS for the new language to be used. + + + + + Language change failed + + + + + The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code... + + + + + MainWindow + + + Alber + + + + + File + + + + + Emulation + + + + + Tools + + + + + About + + + + + Load game + + + + + Load Lua script + + + + + Open Panda3DS folder + + + + + Pause + + + + + Resume + + + + + Reset + + + + + Configure + + + + + Dump RomFS + + + + + Open Lua Editor + + + + + Open Cheats Editor + + + + + Open Patch Window + + + + + Open Shader Editor + + + + + Dump loaded DSP firmware + + + + + About Panda3DS + + + + + Select 3DS ROM to load + + + + + Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + + + + + Select Lua script to load + + + + + Lua scripts (*.lua *.txt) + + + + + Select folder to dump RomFS files to + + + + + Invalid format for RomFS dumping + + + + + The currently loaded app is not in a format that supports RomFS + + + + + + + OK + + + + + No RomFS found + + + + + No RomFS partition was found in the loaded app + + + + + Select file + + + + + DSP firmware file (*.cdc) + + + + + No DSP firmware loaded + + + + + The currently loaded app has not uploaded a firmware to the DSP + + + + + Failed to open output file + + + + + The currently loaded DSP firmware could not be written to the selected file. Please make sure you have permission to access this file + + + + + PatchWindow + + + ROM patcher + + + + + Select input file + + + + + + Select + + + + + + Select patch file + + + + + Apply patch + + + + + Select file to patch + + + + + + All files (*.*) + + + + + Patch files (*.ips *.ups *.bps) + + + + + Paths not provided correctly + + + + + Please provide paths for both the input file and the patch file + + + + + Select file + + + + + No output path + + + + + No path was provided for the output file, no patching was done + + + + + Unknown patch format + + + + + Unknown format for patch file. Currently IPS, UPS and BPS are supported + + + + + Failed to open input files + + + + + Make sure they're in a directory Panda3DS has access to + + + + + Patching Success + + + + + Your file was patched successfully. + + + + + Checksum mismatch + + + + + Patch was applied successfully but a checksum mismatch was detected. The input or output files might not be correct + + + + + Patching error + + + + + An error occured while patching + + + + + PatchWindow::PatchWindow + + + OK + + + + + ShaderEditorWindow + + + Reload shader + + + + + TextEditorWindow + + + Lua Editor + + + + + Load script + + + + diff --git a/docs/translations/es.ts b/docs/translations/es.ts new file mode 100644 index 000000000..6f3452614 --- /dev/null +++ b/docs/translations/es.ts @@ -0,0 +1,763 @@ + + + AboutWindow + + + About Panda3DS + Acerca de Panda3DS + + + + Panda3DS is a free and open source Nintendo 3DS emulator, for Windows, MacOS and Linux + Panda3DS es un emulador libre y de código abierto de Nintendo 3DS para Windows, MacOS y Linux + + + + Visit panda3ds.com for help with Panda3DS and links to our official support sites. + Visita panda3ds.com para obtener ayuda con Panda3DS y los links a nuestras páginas oficiales de soporte. + + + + Panda3DS is developed by volunteers in their spare time. Below is a list of some of these volunteers who've agreed to be listed here, in no particular order.<br>If you think you should be listed here too, please inform us<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + Panda3DS es desarrollado por voluntarios en su tiempo libre. Debajo se encuentran los voluntarios que están de acuerdo con ser listados aquí, en ningún orden en particular.<br>Si piensas que deberías ser listado, por favor infórmanos<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + + + + CheatEditDialog + + + Edit Cheat + Editar Truco + + + + Cheat name + Nombre del truco + + + + CheatEntryWidget + + + Edit + Editar + + + + CheatsWindow + + + Cheats + Trucos + + + + Add + Añadir + + + + Remove + Quitar + + + + ConfigWindow + + + Configuration + Configuración + + + + Interface Settings + Configuración de Interfaz + + + + System + Sistema + + + + Light + Claro + + + + Dark + Oscuro + + + + Greetings Cat + + + + + Cream + + + + + Color theme + Tema de color + + + + Happy panda + Panda feliz + + + + Happy panda (colourful) + Panda feliz (colorido) + + + + Sleepy panda + Panda somnoliento + + + + Cow panda + Panda vaca + + + + The penguin from SkyEmu + El pungüino de SkyEmu + + + + Window icon + Icono de ventana + + + + Language + Idioma + + + + Show version on window title + Mostrar versión en la barra de título de la ventana + + + + Alber v%1 + Alber v%1 + + + + Alber + Alber + + + + Remember window position + Recordar posición de la ventana + + + + General Settings + Configuración General + + + + Browse... + Examinar... + + + + Select Directory + Seleccionar Directorio + + + + Default ROMs path + Ruta predeterminada de ROMs + + + + Enable Discord RPC + Activar Discord RPC + + + + Use portable build + Usar build portable + + + + Print version in console output + Imprimir versión en consola + + + + Graphics Settings + Configuración de Gráficos + + + + + Null + Nulo + + + + OpenGL + OpenGL + + + + Vulkan + Vulkan + + + + GPU renderer + Renderizador GPU + + + + Enable Renderdoc + Activar Renderdoc + + + + Enable shader JIT + Activar JIT de shaders + + + + Enable VSync + Activar VSync + + + + Use ubershaders (No stutter, maybe slower) + Usar ubershaders (No stuttering, puede ser más lento) + + + + Accurate shader multiplication + Multiplicación precisa de shaders + + + + Accelerate shaders + Acelerar shaders + + + + Force shadergen when rendering lights + Forzar shadergen al renderizar luces + + + + Light threshold for forcing shadergen + Umbral de luz para forzar shadergen + + + + Audio Settings + Configuración de Audio + + + + LLE + LLE + + + + HLE + HLE + + + + DSP emulation + Emulación de DSP + + + + Enable audio + Activar audio + + + + Enable AAC audio + Activar audio AAC + + + + Print DSP firmware + Imprimir firmware DSP + + + + Mute audio device + Silenciar dispositivo de audio + + + + Cubic + Cúbico + + + + Linear + Linear + + + + Volume curve + Curva del volumen + + + + Audio device volume + Volumen del dispositivo de audio + + + + Battery Settings + Configuración de Batería + + + + Battery percentage + Porcentaje de batería + + + + Charger plugged + Cargador conectado + + + + SD Card Settings + Configuración de Tarjeta SD + + + + Enable virtual SD card + Activar tarjeta SD virtual + + + + Write protect virtual SD card + Proteger tarjeta SD de escritura + + + + Interface + Interfaz + + + + User Interface settings + Configuración de Interfaz de Usuario + + + + General + General + + + + General emulator settings + Configuración general del emulador + + + + Graphics + Gráficos + + + + Graphics emulation and output settings + Configuración de emulación de gráficos y salida de vídeo + + + + Audio + Audio + + + + Audio emulation and output settings + Configuración de emulación y salida de audio + + + + Battery + Batería + + + + Battery emulation settings + Configuración de emulación de la batería + + + + SD Card + Tarjeta SD + + + + SD Card emulation settings + Configuración de emulación de la tarjeta SD + + + + Language change successful + Idioma cambiado correctamente + + + + Restart Panda3DS for the new language to be used. + Reinicie Panda3DS para utilizar el nuevo idioma. + + + + Language change failed + Cambio de idioma fallido + + + + The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code... + El idioma que ha seleccionado no está incluido en Panda3DS. Si está viendo esto, alguien cometió un error en el código... + + + + MainWindow + + + Alber + Alber + + + + File + Archivo + + + + Emulation + Emulación + + + + Tools + Herramientas + + + + About + Acerca de + + + + Load game + Cargar juego + + + + Load Lua script + Cargar script Lua + + + + Open Panda3DS folder + Abrir carpeta Panda3DS + + + + Pause + Pausar + + + + Resume + Reanudar + + + + Reset + Reiniciar + + + + Configure + Configurar + + + + Dump RomFS + Volcar RomFS + + + + Open Lua Editor + Abrir Editor Lua + + + + Open Cheats Editor + Abrir Editor de Trucos + + + + Open Patch Window + Abrir Ventana de Parches + + + + Open Shader Editor + Abrir Editor de Shaders + + + + Dump loaded DSP firmware + Volcar firmware DSP cargado + + + + About Panda3DS + Acerca de Panda3DS + + + + Select 3DS ROM to load + Seleccione el ROM de 3DS a cargar + + + + Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + ROMs de Nintendo 3DS (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + + + + Select Lua script to load + Seleccione el script Lua a cargar + + + + Lua scripts (*.lua *.txt) + Scripts Lua (*.lua *.txt) + + + + Select folder to dump RomFS files to + Seleccione la carpeta donde volcar los archivos del RomFS + + + + Invalid format for RomFS dumping + Formato inváido para volcado de RomFS + + + + The currently loaded app is not in a format that supports RomFS + La aplicación cargada no tiene un formato que soporta RomFS + + + + + + OK + OK + + + + No RomFS found + RomFS no encontrado + + + + No RomFS partition was found in the loaded app + No se encontró una partición RomFS en la aplicación cargada + + + + Select file + Seleccionar archivo + + + + DSP firmware file (*.cdc) + Archivo de firmware DSP (*.cdc) + + + + No DSP firmware loaded + Firmware DSP no cargado + + + + The currently loaded app has not uploaded a firmware to the DSP + La aplicación cargada no ha subido un firmware al DSP + + + + Failed to open output file + Error al abrir el archivo de salida + + + + The currently loaded DSP firmware could not be written to the selected file. Please make sure you have permission to access this file + No se pudo escribir el firmware DSP cargado al archivo seleccionado. Por favor asegure que tiene los permisos necesarios para acceder a este archivo + + + + PatchWindow + + + ROM patcher + Parcheador de ROM + + + + Select input file + Seleccione el archivo de entrada + + + + + Select + Seleccionar + + + + + Select patch file + Seleccione el archivo de parche + + + + Apply patch + Aplicar parche + + + + Select file to patch + Seleccione el archivo a parchear + + + + + All files (*.*) + Todos los archivos (*.*) + + + + Patch files (*.ips *.ups *.bps) + Archivos de parche (*.ips *.ups *.bps) + + + + Paths not provided correctly + Rutas no proporcionadas correctamente + + + + Please provide paths for both the input file and the patch file + Por favor proporcione rutas para el archivo de entrada y el parche + + + + Select file + Seleccionar archivo + + + + No output path + No hay archivo de salida + + + + No path was provided for the output file, no patching was done + No se ha proporcionado una ruta para el archivo de salida, no se ha aplicado el parche + + + + Unknown patch format + Formato del parche desconocido + + + + Unknown format for patch file. Currently IPS, UPS and BPS are supported + Formato desconocido del archivo de parche. Actualmente son soportados IPS, UPS y BPS + + + + Failed to open input files + Error al abrir archivos de entrada + + + + Make sure they're in a directory Panda3DS has access to + Asegure que estén en un directorio al que Panda3DS tenga acceso + + + + Patching Success + Parche exitoso + + + + Your file was patched successfully. + Su archivo fue parcheado con éxito. + + + + Checksum mismatch + Discrepancia en la suma de verificación + + + + Patch was applied successfully but a checksum mismatch was detected. The input or output files might not be correct + El parche se aplicó con éxito pero se detectó una discrepancia en la suma de verificación. Los archivos de entrada o salida pueden no ser correctos + + + + Patching error + Error de parcheo + + + + An error occured while patching + Ha ocurrido un error en el parcheo + + + + PatchWindow::PatchWindow + + + OK + OK + + + + ShaderEditorWindow + + + Reload shader + Recargar shader + + + + TextEditorWindow + + + Lua Editor + Editor Lua + + + + Load script + Cargar script + + + \ No newline at end of file diff --git a/docs/translations/nl.ts b/docs/translations/nl.ts new file mode 100644 index 000000000..4e6d3e9e5 --- /dev/null +++ b/docs/translations/nl.ts @@ -0,0 +1,763 @@ + + + AboutWindow + + + About Panda3DS + Over Panda3DS + + + + Panda3DS is a free and open source Nintendo 3DS emulator, for Windows, MacOS and Linux + Panda3DS is een gratis, open source Nintendo 3DS-emulator voor Windows, MacOS en Linux + + + + Visit panda3ds.com for help with Panda3DS and links to our official support sites. + Bezoek panda3ds.com voor ondersteuning van Panda3DS en links naar onze officiële ondersteuningskanalen. + + + + Panda3DS is developed by volunteers in their spare time. Below is a list of some of these volunteers who've agreed to be listed here, in no particular order.<br>If you think you should be listed here too, please inform us<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + Panda3DS wordt ontwikkeld door vrijwilligers in hun vrije tijd. Hieronder een lijst van sommige van deze vrijwilligers die akkoord zijn met een vermelding, in willekeurige volgorde.<br>Als jij vindt dat je op deze lijst zou moeten staan, laat het ons dan weten<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + + + + CheatEditDialog + + + Edit Cheat + Cheat bewerken + + + + Cheat name + Cheatnaam + + + + CheatEntryWidget + + + Edit + Bewerken + + + + CheatsWindow + + + Cheats + Cheats + + + + Add + Toevoegen + + + + Remove + Verwijderen + + + + ConfigWindow + + + Configuration + Instellingen + + + + Interface Settings + Interfaceinstellingen + + + + System + Systeem + + + + Light + Licht + + + + Dark + Donker + + + + Greetings Cat + Begroetingskat + + + + Cream + Crème + + + + Color theme + Kleurenthema + + + + Happy panda + Blije panda + + + + Happy panda (colourful) + Blije panda (kleurrijk) + + + + Sleepy panda + Slaperige panda + + + + Cow panda + Koeienpanda + + + + The penguin from SkyEmu + De pinguïn van SkyEmu + + + + Window icon + Venstericoon + + + + Language + Taal + + + + Show version on window title + Toon versie in venstertitel + + + + Alber v%1 + Alber v%1 + + + + Alber + Alber + + + + Remember window position + Vensterpositie onthouden + + + + General Settings + Algemene instellingen + + + + Browse... + Bladeren... + + + + Select Directory + Kies map + + + + Default ROMs path + Standaard pad voor ROMs + + + + Enable Discord RPC + Discord RPC inschakelen + + + + Use portable build + Portable build gebruiken + + + + Print version in console output + Versie afdrukken in consoleuitvoer + + + + Graphics Settings + Grafische instellingen + + + + + Null + Null + + + + OpenGL + OpenGL + + + + Vulkan + Vulkan + + + + GPU renderer + Renderen op videokaart + + + + Enable Renderdoc + Renderdoc inschakelen + + + + Enable shader JIT + Shader JIT inschakelen + + + + Enable VSync + VSync inschakelen + + + + Use ubershaders (No stutter, maybe slower) + Ubershaders gebruiken (geen haperingen, mogelijk langzamer) + + + + Accurate shader multiplication + Nauwkeurige vermenigvuldigen in shaders + + + + Accelerate shaders + Shaders versnellen + + + + Force shadergen when rendering lights + Shadergen afdwingen bij tekenen licht + + + + Light threshold for forcing shadergen + Lichtgrens voor afdwingen shadergen + + + + Audio Settings + Audioinstellingen + + + + LLE + LLE + + + + HLE + HLE + + + + DSP emulation + DSP-emulatie + + + + Enable audio + Audio inschakelen + + + + Enable AAC audio + AAC-audio inschakelen + + + + Print DSP firmware + DSP-firmware afdrukken + + + + Mute audio device + Audioapparaat dempen + + + + Cubic + Kubiek + + + + Linear + Lineair + + + + Volume curve + Volumecurve + + + + Audio device volume + Volume audioapparaat + + + + Battery Settings + Batterij-instellingen + + + + Battery percentage + Batterijpercentage + + + + Charger plugged + Oplader aangesloten + + + + SD Card Settings + Instellingen SD-kaart + + + + Enable virtual SD card + Virtuele SD-kaart inschakelen + + + + Write protect virtual SD card + Virtuele SD-kaart schrijfbeveiligen + + + + Interface + Interface + + + + User Interface settings + Instellingen gebruikersinterface + + + + General + Algemeen + + + + General emulator settings + Algemene emulatorinstellingen + + + + Graphics + Weergave + + + + Graphics emulation and output settings + Instellingen grafische emulatie en weergave + + + + Audio + Audio + + + + Audio emulation and output settings + Instellingen audioemulatie en weergave + + + + Battery + Batterij + + + + Battery emulation settings + Instellingen batterijemulatie + + + + SD Card + SD-kaart + + + + SD Card emulation settings + Instellingen SD-kaart-emulatie + + + + Language change successful + Taal succesvol ingesteld + + + + Restart Panda3DS for the new language to be used. + Herstart Panda3DS om de nieuw gekozen taal te gebruiken. + + + + Language change failed + Wijzigen van taal mislukt + + + + The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code... + De gekozen taal is niet beschikbaar in Panda3DS. Als je dit leest heeft iemand de taalcode verprutst... + + + + MainWindow + + + Alber + Alber + + + + File + Bestand + + + + Emulation + Emulatie + + + + Tools + Hulpmiddelen + + + + About + Over + + + + Load game + Spel laden + + + + Load Lua script + LUA-script laden + + + + Open Panda3DS folder + Open Panda3DS-map + + + + Pause + Pauzeren + + + + Resume + Hervatten + + + + Reset + Reset + + + + Configure + Instellingen + + + + Dump RomFS + RomFS dumpen + + + + Open Lua Editor + Open LUA-editor + + + + Open Cheats Editor + Open cheats-editor + + + + Open Patch Window + Open patchvenster + + + + Open Shader Editor + Open shader-editor + + + + Dump loaded DSP firmware + Geladen DSP-firmware dumpen + + + + About Panda3DS + Over Panda3DS + + + + Select 3DS ROM to load + Kies 3DS ROM om te laden + + + + Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + + + + Select Lua script to load + Kies LUA-script om te laden + + + + Lua scripts (*.lua *.txt) + LUA-scripts (*.lua *.txt) + + + + Select folder to dump RomFS files to + Kies map om RomFS-bestanden heen te dumpen + + + + Invalid format for RomFS dumping + Ongeldig formaat voor RomFS dump + + + + The currently loaded app is not in a format that supports RomFS + Het formaat van de momenteel geladen applicatie ondersteunt geen RomFS + + + + + + OK + OK + + + + No RomFS found + Geen RomFS gevonden + + + + No RomFS partition was found in the loaded app + Geen RomFS-partitie gevonden in de geladen applicatie + + + + Select file + Selecteer bestand + + + + DSP firmware file (*.cdc) + DSP-firmware-bestand (*.cdc) + + + + No DSP firmware loaded + Geen DSP-firmware geladen + + + + The currently loaded app has not uploaded a firmware to the DSP + De momenteel geladen applicatie heeft geen firmware geüpload naar de DSP + + + + Failed to open output file + Uitvoerbestand openen mislukt + + + + The currently loaded DSP firmware could not be written to the selected file. Please make sure you have permission to access this file + De momenteel geladen DSP-firmware kan niet worden geschreven naar het gekozen bestand. Controleer de permissies van het gekozen bestand + + + + PatchWindow + + + ROM patcher + ROM-patcher + + + + Select input file + Kies invoerbestand + + + + + Select + Kies + + + + + Select patch file + Kies patchbestand + + + + Apply patch + Patch toepassen + + + + Select file to patch + Kies bestand om te patchen + + + + + All files (*.*) + Alle bestanden (*.*) + + + + Patch files (*.ips *.ups *.bps) + Patch-bestanden (*.ips *.ups *.bps) + + + + Paths not provided correctly + Paden incorrect meegegeven + + + + Please provide paths for both the input file and the patch file + Geef paden van invoerbestand en patchbestand op + + + + Select file + Kies bestand + + + + No output path + Geen uitvoerpad + + + + No path was provided for the output file, no patching was done + Geen pad opgegeven voor uitvoerbestand, patch niet toegepast + + + + Unknown patch format + Onbekend patchformaat + + + + Unknown format for patch file. Currently IPS, UPS and BPS are supported + Ongeldig formaat van patchbestand. Momenteel wordt IPS, UPS en BPS ondersteund + + + + Failed to open input files + Openen van invoerbestanden mislukt + + + + Make sure they're in a directory Panda3DS has access to + Zorg ervoor dat ze in een map staan waar Panda3DS toegang toe heeft + + + + Patching Success + Patch succesvol + + + + Your file was patched successfully. + Het bestand is succesvol gepatcht. + + + + Checksum mismatch + Checksum komt niet overeen + + + + Patch was applied successfully but a checksum mismatch was detected. The input or output files might not be correct + Patch is succesvol toegepast maar de checksum komt niet overeen. Invoer- of uitvoerbestand is mogelijk ongeldig + + + + Patching error + Fout tijdens patchen + + + + An error occured while patching + Er is bij het patchen een fout opgetreden + + + + PatchWindow::PatchWindow + + + OK + OK + + + + ShaderEditorWindow + + + Reload shader + Shader herladen + + + + TextEditorWindow + + + Lua Editor + LUA-editor + + + + Load script + Script laden + + + \ No newline at end of file diff --git a/docs/translations/pt_br.ts b/docs/translations/pt_br.ts new file mode 100644 index 000000000..e2afe3a97 --- /dev/null +++ b/docs/translations/pt_br.ts @@ -0,0 +1,764 @@ + + + AboutWindow + + + About Panda3DS + Sobre o Panda3DS + + + + Panda3DS is a free and open source Nintendo 3DS emulator, for Windows, MacOS and Linux + Panda3DS é um emulador gratuito e open-source para Windows, MacOS e Linux + + + + Visit panda3ds.com for help with Panda3DS and links to our official support sites. + Visite panda3ds.com para obter ajuda e links de suporte oficial. + + + + Panda3DS is developed by volunteers in their spare time. Below is a list of some of these volunteers who've agreed to be listed here, in no particular order.<br>If you think you should be listed here too, please inform us<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + Panda3DS é desenvolvido por voluntários em seu tempo livre. Abaixo a lista de alguns volutário<br>(Lista sem nenhuma ordem específica)<br>Se acha que seu nome deveria estar listado aqui por favor informe-nos<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + + + + CheatEditDialog + + + Edit Cheat + Editar Trapaças + + + + Cheat name + Nome da trapaça + + + + CheatEntryWidget + + + Edit + Editar + + + + CheatsWindow + + + Cheats + Trapaça + + + + Add + Adicionar + + + + Remove + Sair + + + + ConfigWindow + + + Configuration + Configurações + + + + Interface Settings + Configurações da interface + + + + System + Sistema + + + + Light + Claro + + + + Dark + Escuro + + + + Greetings Cat + + + + + Cream + + + + + Color theme + Tema de color + + + + Happy panda + Panda feliz + + + + Happy panda (colourful) + Panda feliz (colorido) + + + + Sleepy panda + Panda sonolento + + + + Cow panda + Panda vaca + + + + The penguin from SkyEmu + O pinguim do SkyEmu + + + + Window icon + Icone da janela + + + + Language + Idioma + + + + Show version on window title + Mostrar versão na barra de título + + + + Alber v%1 + Alber v%1 + + + + Alber + Alber + + + + Remember window position + Lembrar posição da janela + + + + General Settings + Configurações gerais + + + + Browse... + Navegar... + + + + Select Directory + Selecionar o diretório + + + + Default ROMs path + Diretório padrão das ROMs + + + + Enable Discord RPC + Ativar Discord RPC + + + + Use portable build + Usar build portatil + + + + Print version in console output + Imprimir versão no console + + + + Graphics Settings + Configurações gráficas + + + + + Null + Nulo + + + + OpenGL + OpenGL + + + + Vulkan + Vulkan + + + + GPU renderer + Renderizador GPU + + + + Enable Renderdoc + Ativar Renderdoc + + + + Enable shader JIT + Ativar JIT de shaders + + + + Enable VSync + Ativar VSync + + + + Use ubershaders (No stutter, maybe slower) + Usar ubershaders (No stuttering, puede ser más lento) + + + + Accurate shader multiplication + Multiplicação precisa de shaders + + + + Accelerate shaders + Graficos acelerados + + + + Force shadergen when rendering lights + Forçar shadergen ao renderizar luzes. + + + + Light threshold for forcing shadergen + Limear de luzes para forçar shadergen + + + + Audio Settings + Configurações de audio + + + + LLE + LLE + + + + HLE + HLE + + + + DSP emulation + Emulação DSP + + + + Enable audio + Ativar audio + + + + Enable AAC audio + Ativar audio AAC + + + + Print DSP firmware + Imprimir firmware DSP + + + + Mute audio device + Silenciar dispositivo de audio + + + + Cubic + Cúbico + + + + Linear + Linear + + + + Volume curve + Curva de volume + + + + Audio device volume + Volume do dispositivo de audio + + + + Battery Settings + Configurações de bateria + + + + Battery percentage + Porcentagem da bateria + + + + Charger plugged + Carregador conectado + + + + SD Card Settings + Configurações do cartão de memoria + + + + Enable virtual SD card + Ativar cartão de memoria virtual + + + + Write protect virtual SD card + Proteger cartão de memoria virtual contra escrita + + + + Interface + Interface + + + + User Interface settings + Configurações da interface de usuario + + + + General + Geral + + + + General emulator settings + Configurações gerais do emulador + + + + Graphics + Gráficos + + + + Graphics emulation and output settings + Configurações da emulação e saida de video + + + + Audio + Audio + + + + Audio emulation and output settings + Configurações da emulação e saida de audio + + + + Battery + Bateria + + + + Battery emulation settings + Configuração da emulação da bateria + + + + SD Card + Cartão de memoria + + + + SD Card emulation settings + Configurar a emulação do cartão de memoria + + + + Language change successful + Idioma alterado com sucesso + + + + Restart Panda3DS for the new language to be used. + Para aplicar o novo idioma feche e abra o emulador. + + + + Language change failed + A mudaça de idioma falhou + + + + The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code... + O idioma selecionado não existe no Panda3DS. Se você esta vendo esse erro existe um erro no codigo... + + + + MainWindow + + + Alber + Alber + + + + File + Arquivo + + + + Emulation + Emulação + + + + Tools + Ferramentas + + + + About + Sobre + + + + Load game + Carregar jogo + + + + Load Lua script + Carregar Script Lua + + + + Open Panda3DS folder + Abrir pasta do Panda3DS + + + + Pause + Pausar + + + + Resume + Continuar + + + + Reset + Reiniciar + + + + Configure + Configurar + + + + Dump RomFS + Extrair RomFS + + + + Open Lua Editor + Abrir editor Lua + + + + Open Cheats Editor + Abrir editor de trapaças + + + + Open Patch Window + Abrir janela de trapaças + + + + Open Shader Editor + Abrir editor de shaders + + + + Dump loaded DSP firmware + Extrair firmware DSP carregado + + + + About Panda3DS + Sobre o Panda3DS + + + + Select 3DS ROM to load + Selecione uma ROM de 3DS para carregar + + + + Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + ROMs de Nintendo 3DS (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + + + + Select Lua script to load + Selecione uma ROM de 3DS para carregar + + + + Lua scripts (*.lua *.txt) + Scripts Lua (*.lua *.txt) + + + + Select folder to dump RomFS files to + Selecione onde a RomFS será extraida + + + + Invalid format for RomFS dumping + Formato de RomFS inválido + + + + The currently loaded app is not in a format that supports RomFS + O aplicativo carregado não suporta RomFS + + + + + + OK + OK + + + + No RomFS found + RomFS no encontrado + + + + No RomFS partition was found in the loaded app + A partição RomFS não foi encontrada no aplicativo + + + + Select file + Selecionar arquivo + + + + DSP firmware file (*.cdc) + Arquivo do firmware DSP (*.cdc) + + + + No DSP firmware loaded + Nenhum firmware DSP carregado + + + + The currently loaded app has not uploaded a firmware to the DSP + A aplicação não carregou um firmware DSP + + + + Failed to open output file + Erro ao abrir arquvio de destino + + + + The currently loaded DSP firmware could not be written to the selected file. Please make sure you have permission to access this file + O firmware DSP carregado não pode escrever no arquivo selecionado. Porfavor veja se você tem permissão para modificalo-lo. + + + + PatchWindow + + + ROM patcher + Editor de ROM + + + + Select input file + Selecione o arquivo de entrada + + + + + Select + Selecionar + + + + + Select patch file + Seleciona um arquivo de patch + + + + Apply patch + Aplicar patch + + + + Select file to patch + Selecione um arquivo para editar + + + + + All files (*.*) + Todos os arquivos (*.*) + + + + Patch files (*.ips *.ups *.bps) + Arquivos de patch (*.ips *.ups *.bps) + + + + Paths not provided correctly + Diretórios não fornecidos corretamente + + + + Please provide paths for both the input file and the patch file + Por favor selecione os diretórios tanto para o arquivo de origem como para o patch + + + + Select file + Selecionar arquivo + + + + No output path + Sem diretório de saida + + + + No path was provided for the output file, no patching was done + Nenhum diretorio de destino foi fornecido, patch não aplicado. + + + + Unknown patch format + Formato de patch desconhecido + + + + Unknown format for patch file. Currently IPS, UPS and BPS are supported + Arquivo de patch inválido. Atualmete são suportado patches nos formatos IPS, UPS e BPS + + + + Failed to open input files + Falha ao abrir os arquivos + + + + Make sure they're in a directory Panda3DS has access to + Certifique-se de que eles estejam em um diretório ao qual o Panda3DS tenha acesso + + + + Patching Success + Patch aplicado + + + + Your file was patched successfully. + O patch foi aplicado com sucesso ao arquivo + + + + Checksum mismatch + Checagem inválido + + + + Patch was applied successfully but a checksum mismatch was detected. The input or output files might not be correct + O patch foi aplicado com sucesso porem a checagem falhou. O arquivo de origem ou destino pode não estar correto. + + + + Patching error + Erro de patch + + + + An error occured while patching + Um erro ocorreu ao aplicar o patch + + + + PatchWindow::PatchWindow + + + OK + OK + + + + ShaderEditorWindow + + + Reload shader + Recargar shader + + + + TextEditorWindow + + + Lua Editor + Editor Lua + + + + Load script + Cargar script + + + + diff --git a/include/audio/miniaudio_device.hpp b/include/audio/miniaudio_device.hpp index 516c16025..0363aa441 100644 --- a/include/audio/miniaudio_device.hpp +++ b/include/audio/miniaudio_device.hpp @@ -36,4 +36,6 @@ class MiniAudioDevice { void start(); void stop(); + + bool isInitialized() const { return initialized; } }; \ No newline at end of file diff --git a/include/frontend_settings.hpp b/include/frontend_settings.hpp index 1a78ab66f..ae9678792 100644 --- a/include/frontend_settings.hpp +++ b/include/frontend_settings.hpp @@ -24,6 +24,7 @@ struct FrontendSettings { Theme theme = Theme::Dark; WindowIcon icon = WindowIcon::Rpog; + std::string language = "en"; static Theme themeFromString(std::string inString); static const char* themeToString(Theme theme); diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index 2843be687..d899d1a6e 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -7,6 +7,7 @@ #include #include #include + #include "helpers.hpp" #include "memory.hpp" #include "result.hpp" @@ -15,13 +16,13 @@ using Result::HorizonResult; namespace PathType { - enum : u32 { - Invalid = 0, - Empty = 1, - Binary = 2, - ASCII = 3, - UTF16 = 4, - }; + enum : u32 { + Invalid = 0, + Empty = 1, + Binary = 2, + ASCII = 3, + UTF16 = 4, + }; } namespace ArchiveID { @@ -34,91 +35,95 @@ namespace ArchiveID { SDMC = 9, SDMCWriteOnly = 0xA, + CardSPI = 0x12345679, SavedataAndNcch = 0x2345678A, // 3DBrew: This is the same as the regular SaveData archive, except with this the savedata ID and mediatype is loaded from the input archive // lowpath. UserSaveData1 = 0x567890B2, // 3DBrew: Similar to 0x567890B2 but can only access Accessible Save specified in exheader? UserSaveData2 = 0x567890B4, + + TwlPhoto = 0x567890AC, + TwlSound = 0x567890AD, }; - static std::string toString(u32 id) { - switch (id) { - case SelfNCCH: return "SelfNCCH"; - case SaveData: return "SaveData"; - case ExtSaveData: return "ExtSaveData"; - case SharedExtSaveData: return "SharedExtSaveData"; - case SystemSaveData: return "SystemSaveData"; - case SDMC: return "SDMC"; - case SDMCWriteOnly: return "SDMC (Write-only)"; - case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)"; - default: return "Unknown archive"; - } - } -} + static std::string toString(u32 id) { + switch (id) { + case SelfNCCH: return "SelfNCCH"; + case SaveData: return "SaveData"; + case ExtSaveData: return "ExtSaveData"; + case SharedExtSaveData: return "SharedExtSaveData"; + case SystemSaveData: return "SystemSaveData"; + case SDMC: return "SDMC"; + case SDMCWriteOnly: return "SDMC (Write-only)"; + case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)"; + case TwlPhoto: return "TWL_PHOTO"; + case TwlSound: return "TWL_SOUND"; + default: return "Unknown archive"; + } + } +} // namespace ArchiveID struct FSPath { - u32 type = PathType::Invalid; - - std::vector binary; // Path data for binary paths - std::string string; // Path data for ASCII paths - std::u16string utf16_string; - - FSPath() {} - - FSPath(u32 type, const std::vector& vec) : type(type) { - switch (type) { - case PathType::Binary: - binary = std::move(vec); - break; - - case PathType::ASCII: - string.resize(vec.size() - 1); // -1 because of the null terminator - std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data - break; - - case PathType::UTF16: { - const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too - utf16_string.resize(size); - std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16)); - break; - } -; } - } + u32 type = PathType::Invalid; + + std::vector binary; // Path data for binary paths + std::string string; // Path data for ASCII paths + std::u16string utf16_string; + + FSPath() {} + + FSPath(u32 type, const std::vector& vec) : type(type) { + switch (type) { + case PathType::Binary: binary = std::move(vec); break; + + case PathType::ASCII: + string.resize(vec.size() - 1); // -1 because of the null terminator + std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data + break; + + case PathType::UTF16: { + const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too + utf16_string.resize(size); + std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16)); + break; + }; + } + } }; struct FilePerms { - u32 raw; + u32 raw; - FilePerms(u32 val) : raw(val) {} - bool read() const { return (raw & 1) != 0; } - bool write() const { return (raw & 2) != 0; } - bool create() const { return (raw & 4) != 0; } + FilePerms(u32 val) : raw(val) {} + bool read() const { return (raw & 1) != 0; } + bool write() const { return (raw & 2) != 0; } + bool create() const { return (raw & 4) != 0; } }; class ArchiveBase; struct FileSession { - ArchiveBase* archive = nullptr; - FILE* fd = nullptr; // File descriptor for file sessions that require them. - FSPath path; - FSPath archivePath; - u32 priority = 0; // TODO: What does this even do - bool isOpen; - - FileSession(ArchiveBase* archive, const FSPath& filePath, const FSPath& archivePath, FILE* fd, bool isOpen = true) : - archive(archive), path(filePath), archivePath(archivePath), fd(fd), isOpen(isOpen), priority(0) {} - - // For cloning a file session - FileSession(const FileSession& other) : archive(other.archive), path(other.path), - archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {} + ArchiveBase* archive = nullptr; + FILE* fd = nullptr; // File descriptor for file sessions that require them. + FSPath path; + FSPath archivePath; + u32 priority = 0; // TODO: What does this even do + bool isOpen; + + FileSession(ArchiveBase* archive, const FSPath& filePath, const FSPath& archivePath, FILE* fd, bool isOpen = true) + : archive(archive), path(filePath), archivePath(archivePath), fd(fd), isOpen(isOpen), priority(0) {} + + // For cloning a file session + FileSession(const FileSession& other) + : archive(other.archive), path(other.path), archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {} }; struct ArchiveSession { - ArchiveBase* archive = nullptr; - FSPath path; - bool isOpen; + ArchiveBase* archive = nullptr; + FSPath path; + bool isOpen; - ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {} + ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {} }; struct DirectoryEntry { @@ -156,106 +161,104 @@ struct DirectorySession { using FileDescriptor = std::optional; class ArchiveBase { -public: - struct FormatInfo { - u32 size; // Archive size - u32 numOfDirectories; // Number of directories - u32 numOfFiles; // Number of files - bool duplicateData; // Whether to duplicate data or not - }; - -protected: - using Handle = u32; - - static constexpr FileDescriptor NoFile = nullptr; - static constexpr FileDescriptor FileError = std::nullopt; - Memory& mem; - - // Returns if a specified 3DS path in UTF16 or ASCII format is safe or not - // A 3DS path is considered safe if its first character is '/' which means we're not trying to access anything outside the root of the fs - // And if it doesn't contain enough instances of ".." (Indicating "climb up a folder" in filesystems) to let the software climb up the directory tree - // And access files outside of the emulator's app data folder - template - bool isPathSafe(const FSPath& path) { - static_assert(format == PathType::ASCII || format == PathType::UTF16); - using String = typename std::conditional::type; // String type for the path - using Char = typename String::value_type; // Char type for the path - - String pathString, dots; - if constexpr (std::is_same()) { - pathString = path.utf16_string; - dots = u".."; - } else { - pathString = path.string; - dots = ".."; - } - - // If the path string doesn't begin with / then that means it's accessing outside the FS root, which is invalid & unsafe - if (pathString[0] != Char('/')) return false; - - // Counts how many folders sans the root our file is nested under. - // If it's < 0 at any point of parsing, then the path is unsafe and tries to crawl outside our file sandbox. - // If it's 0 then this is the FS root. - // If it's > 0 then we're in a subdirectory of the root. - int level = 0; - - // Split the string on / characters and see how many of the substrings are ".." - size_t pos = 0; - while ((pos = pathString.find(Char('/'))) != String::npos) { - String token = pathString.substr(0, pos); - pathString.erase(0, pos + 1); - - if (token == dots) { - level--; - if (level < 0) return false; - } else { - level++; - } - } - - return true; - } - -public: - virtual std::string name() = 0; - virtual u64 getFreeBytes() = 0; - virtual HorizonResult createFile(const FSPath& path, u64 size) = 0; - virtual HorizonResult deleteFile(const FSPath& path) = 0; - - virtual Rust::Result getFormatInfo(const FSPath& path) { - Helpers::panic("Unimplemented GetFormatInfo for %s archive", name().c_str()); - // Return a dummy struct just to avoid the UB of not returning anything, even if we panic - return Ok(FormatInfo{ .size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false }); - } - - virtual HorizonResult createDirectory(const FSPath& path) { - Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str()); - return Result::FS::AlreadyExists; - } - - // Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed) - virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0; - virtual Rust::Result openArchive(const FSPath& path) = 0; - - virtual Rust::Result openDirectory(const FSPath& path) { - Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str()); - return Err(Result::FS::FileNotFoundAlt); - } - - virtual void format(const FSPath& path, const FormatInfo& info) { - Helpers::panic("Unimplemented Format for %s archive", name().c_str()); - } - - virtual HorizonResult renameFile(const FSPath& oldPath, const FSPath& newPath) { + public: + struct FormatInfo { + u32 size; // Archive size + u32 numOfDirectories; // Number of directories + u32 numOfFiles; // Number of files + bool duplicateData; // Whether to duplicate data or not + }; + + protected: + using Handle = u32; + + static constexpr FileDescriptor NoFile = nullptr; + static constexpr FileDescriptor FileError = std::nullopt; + Memory& mem; + + // Returns if a specified 3DS path in UTF16 or ASCII format is safe or not + // A 3DS path is considered safe if its first character is '/' which means we're not trying to access anything outside the root of the fs + // And if it doesn't contain enough instances of ".." (Indicating "climb up a folder" in filesystems) to let the software climb up the directory + // tree And access files outside of the emulator's app data folder + template + bool isPathSafe(const FSPath& path) { + static_assert(format == PathType::ASCII || format == PathType::UTF16); + using String = typename std::conditional::type; // String type for the path + using Char = typename String::value_type; // Char type for the path + + String pathString, dots; + if constexpr (std::is_same()) { + pathString = path.utf16_string; + dots = u".."; + } else { + pathString = path.string; + dots = ".."; + } + + // If the path string doesn't begin with / then that means it's accessing outside the FS root, which is invalid & unsafe + if (pathString[0] != Char('/')) return false; + + // Counts how many folders sans the root our file is nested under. + // If it's < 0 at any point of parsing, then the path is unsafe and tries to crawl outside our file sandbox. + // If it's 0 then this is the FS root. + // If it's > 0 then we're in a subdirectory of the root. + int level = 0; + + // Split the string on / characters and see how many of the substrings are ".." + size_t pos = 0; + while ((pos = pathString.find(Char('/'))) != String::npos) { + String token = pathString.substr(0, pos); + pathString.erase(0, pos + 1); + + if (token == dots) { + level--; + if (level < 0) return false; + } else { + level++; + } + } + + return true; + } + + public: + virtual std::string name() = 0; + virtual u64 getFreeBytes() = 0; + virtual HorizonResult createFile(const FSPath& path, u64 size) = 0; + virtual HorizonResult deleteFile(const FSPath& path) = 0; + + virtual Rust::Result getFormatInfo(const FSPath& path) { + Helpers::panic("Unimplemented GetFormatInfo for %s archive", name().c_str()); + // Return a dummy struct just to avoid the UB of not returning anything, even if we panic + return Ok(FormatInfo{.size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false}); + } + + virtual HorizonResult createDirectory(const FSPath& path) { + Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str()); + return Result::FS::AlreadyExists; + } + + // Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed) + virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0; + virtual Rust::Result openArchive(const FSPath& path) = 0; + + virtual Rust::Result openDirectory(const FSPath& path) { + Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str()); + return Err(Result::FS::FileNotFoundAlt); + } + + virtual void format(const FSPath& path, const FormatInfo& info) { Helpers::panic("Unimplemented Format for %s archive", name().c_str()); } + + virtual HorizonResult renameFile(const FSPath& oldPath, const FSPath& newPath) { Helpers::panic("Unimplemented RenameFile for %s archive", name().c_str()); return Result::Success; - } + } - // Read size bytes from a file starting at offset "offset" into a certain buffer in memory - // Returns the number of bytes read, or nullopt if the read failed - virtual std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0; + // Read size bytes from a file starting at offset "offset" into a certain buffer in memory + // Returns the number of bytes read, or nullopt if the read failed + virtual std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0; - ArchiveBase(Memory& mem) : mem(mem) {} + ArchiveBase(Memory& mem) : mem(mem) {} }; struct ArchiveResource { diff --git a/include/fs/archive_card_spi.hpp b/include/fs/archive_card_spi.hpp new file mode 100644 index 000000000..fefa9933f --- /dev/null +++ b/include/fs/archive_card_spi.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "archive_base.hpp" +#include "result/result.hpp" + +using Result::HorizonResult; + +class CardSPIArchive : public ArchiveBase { + public: + CardSPIArchive(Memory& mem) : ArchiveBase(mem) {} + std::string name() override { return "Card SPI"; } + + u64 getFreeBytes() override { + Helpers::warn("Unimplemented GetFreeBytes for Card SPI archive"); + return 0_MB; + } + + HorizonResult createDirectory(const FSPath& path) override; + HorizonResult createFile(const FSPath& path, u64 size) override; + HorizonResult deleteFile(const FSPath& path) override; + + Rust::Result openArchive(const FSPath& path) override; + Rust::Result openDirectory(const FSPath& path) override; + + FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override; + + std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override { + Helpers::panic("Unimplemented ReadFile for Card SPI archive"); + return {}; + }; +}; \ No newline at end of file diff --git a/include/fs/archive_twl_photo.hpp b/include/fs/archive_twl_photo.hpp new file mode 100644 index 000000000..23111e2b2 --- /dev/null +++ b/include/fs/archive_twl_photo.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "archive_base.hpp" +#include "result/result.hpp" + +using Result::HorizonResult; + +class TWLPhotoArchive : public ArchiveBase { + public: + TWLPhotoArchive(Memory& mem) : ArchiveBase(mem) {} + std::string name() override { return "TWL_PHOTO"; } + + u64 getFreeBytes() override { + Helpers::warn("Unimplemented GetFreeBytes for TWLPhoto archive"); + return 32_MB; + } + + HorizonResult createDirectory(const FSPath& path) override; + HorizonResult createFile(const FSPath& path, u64 size) override; + HorizonResult deleteFile(const FSPath& path) override; + + Rust::Result openArchive(const FSPath& path) override; + Rust::Result openDirectory(const FSPath& path) override; + + FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override; + + std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override { + Helpers::panic("Unimplemented ReadFile for TWL_PHOTO archive"); + return {}; + }; +}; \ No newline at end of file diff --git a/include/fs/archive_twl_sound.hpp b/include/fs/archive_twl_sound.hpp new file mode 100644 index 000000000..cc8fc866c --- /dev/null +++ b/include/fs/archive_twl_sound.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "archive_base.hpp" +#include "result/result.hpp" + +using Result::HorizonResult; + +class TWLSoundArchive : public ArchiveBase { + public: + TWLSoundArchive(Memory& mem) : ArchiveBase(mem) {} + std::string name() override { return "TWL_SOUND"; } + + u64 getFreeBytes() override { + Helpers::warn("Unimplemented GetFreeBytes for TWLSound archive"); + return 32_MB; + } + + HorizonResult createDirectory(const FSPath& path) override; + HorizonResult createFile(const FSPath& path, u64 size) override; + HorizonResult deleteFile(const FSPath& path) override; + + Rust::Result openArchive(const FSPath& path) override; + Rust::Result openDirectory(const FSPath& path) override; + + FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override; + + std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override { + Helpers::panic("Unimplemented ReadFile for TWL_SOUND archive"); + return {}; + }; +}; \ No newline at end of file diff --git a/include/panda_qt/config_window.hpp b/include/panda_qt/config_window.hpp index 9c0037534..1d37a8caa 100644 --- a/include/panda_qt/config_window.hpp +++ b/include/panda_qt/config_window.hpp @@ -45,6 +45,8 @@ class ConfigWindow : public QDialog { void setTheme(FrontendSettings::Theme theme); void setIcon(FrontendSettings::WindowIcon icon); + QComboBox* createLanguageSelect(); + public: ConfigWindow(ConfigCallback configCallback, MainWindowCallback windowCallback, const EmulatorConfig& config, QWidget* parent = nullptr); ~ConfigWindow(); diff --git a/include/panda_qt/main_window.hpp b/include/panda_qt/main_window.hpp index eb1cfb16f..ed54ad84d 100644 --- a/include/panda_qt/main_window.hpp +++ b/include/panda_qt/main_window.hpp @@ -126,6 +126,7 @@ class MainWindow : public QMainWindow { void setupControllerSensors(SDL_GameController* controller); void sendMessage(const EmulatorMessage& message); void dispatchMessage(const EmulatorMessage& message); + void loadTranslation(); // Tracks whether we are using an OpenGL-backed renderer or a Vulkan-backed renderer bool usingGL = false; diff --git a/include/services/dsp.hpp b/include/services/dsp.hpp index 7eb9b28b0..3013c94d4 100644 --- a/include/services/dsp.hpp +++ b/include/services/dsp.hpp @@ -44,9 +44,12 @@ class DSPService { size_t totalEventCount; std::vector loadedComponent; + bool headphonesInserted = true; + // Service functions void convertProcessAddressFromDspDram(u32 messagePointer); // Nice function name void flushDataCache(u32 messagePointer); + void forceHeadphoneOut(u32 messagePointer); void getHeadphoneStatus(u32 messagePointer); void getSemaphoreEventHandle(u32 messagePointer); void invalidateDCache(u32 messagePointer); diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 3b3b3d44b..82f07077a 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -1,11 +1,14 @@ #pragma once #include "config.hpp" +#include "fs/archive_card_spi.hpp" #include "fs/archive_ext_save_data.hpp" #include "fs/archive_ncch.hpp" #include "fs/archive_save_data.hpp" #include "fs/archive_sdmc.hpp" #include "fs/archive_self_ncch.hpp" #include "fs/archive_system_save_data.hpp" +#include "fs/archive_twl_photo.hpp" +#include "fs/archive_twl_sound.hpp" #include "fs/archive_user_save_data.hpp" #include "helpers.hpp" #include "kernel_types.hpp" @@ -39,6 +42,10 @@ class FSService { ExtSaveDataArchive sharedExtSaveData_nand; SystemSaveDataArchive systemSaveData; + TWLPhotoArchive twlPhoto; + TWLSoundArchive twlSound; + CardSPIArchive cardSpi; + ArchiveBase* getArchiveFromID(u32 id, const FSPath& archivePath); Rust::Result openArchiveHandle(u32 archiveID, const FSPath& path); Rust::Result openDirectoryHandle(ArchiveBase* archive, const FSPath& path); @@ -87,7 +94,8 @@ class FSService { FSService(Memory& mem, Kernel& kernel, const EmulatorConfig& config) : mem(mem), saveData(mem), sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"), sdmc(mem), sdmcWriteOnly(mem, true), selfNcch(mem), ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1), - userSaveData2(mem, ArchiveID::UserSaveData2), kernel(kernel), config(config), systemSaveData(mem) {} + userSaveData2(mem, ArchiveID::UserSaveData2), systemSaveData(mem), twlPhoto(mem), twlSound(mem), cardSpi(mem), kernel(kernel), + config(config) {} void reset(); void handleSyncRequest(u32 messagePointer); diff --git a/include/services/gsp_gpu.hpp b/include/services/gsp_gpu.hpp index d72446097..8294565b1 100644 --- a/include/services/gsp_gpu.hpp +++ b/include/services/gsp_gpu.hpp @@ -1,6 +1,7 @@ #pragma once #include #include + #include "PICA/gpu.hpp" #include "helpers.hpp" #include "kernel_types.hpp" @@ -9,12 +10,12 @@ #include "result/result.hpp" enum class GPUInterrupt : u8 { - PSC0 = 0, // Memory fill completed - PSC1 = 1, // ? - VBlank0 = 2, // ? - VBlank1 = 3, // ? - PPF = 4, // Display transfer finished - P3D = 5, // Command list processing finished + PSC0 = 0, // Memory fill completed + PSC1 = 1, // ? + VBlank0 = 2, // ? + VBlank1 = 3, // ? + PPF = 4, // Display transfer finished + P3D = 5, // Command list processing finished DMA = 6 }; @@ -28,8 +29,8 @@ class GPUService { Memory& mem; GPU& gpu; Kernel& kernel; - u32& currentPID; // Process ID of the current process - u8* sharedMem; // Pointer to GSP shared memory + u32& currentPID; // Process ID of the current process + u8* sharedMem; // Pointer to GSP shared memory // At any point in time only 1 process has privileges to use rendering functions // This is the PID of that process @@ -64,8 +65,8 @@ class GPUService { // Used for saving and restoring GPU state via ImportDisplayCaptureInfo struct CaptureInfo { - u32 leftFramebuffer; // Left framebuffer VA - u32 rightFramebuffer; // Right framebuffer VA (Top screen only) + u32 leftFramebuffer; // Left framebuffer VA + u32 rightFramebuffer; // Right framebuffer VA (Top screen only) u32 format; u32 stride; }; @@ -74,6 +75,7 @@ class GPUService { // Service commands void acquireRight(u32 messagePointer); void flushDataCache(u32 messagePointer); + void invalidateDataCache(u32 messagePointer); void importDisplayCaptureInfo(u32 messagePointer); void readHwRegs(u32 messagePointer); void registerInterruptRelayQueue(u32 messagePointer); @@ -108,15 +110,14 @@ class GPUService { FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); } FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); } -public: - GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu), - kernel(kernel), currentPID(currentPID) {} + public: + GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu), kernel(kernel), currentPID(currentPID) {} void reset(); void handleSyncRequest(u32 messagePointer); void requestInterrupt(GPUInterrupt type); void setSharedMem(u8* ptr) { sharedMem = ptr; - if (ptr != nullptr) { // Zero-fill shared memory in case the process tries to read stale service data or vice versa + if (ptr != nullptr) { // Zero-fill shared memory in case the process tries to read stale service data or vice versa std::memset(ptr, 0, 0x1000); } } diff --git a/include/services/mcu/mcu_hwc.hpp b/include/services/mcu/mcu_hwc.hpp index 4c6a88305..c2fada28e 100644 --- a/include/services/mcu/mcu_hwc.hpp +++ b/include/services/mcu/mcu_hwc.hpp @@ -17,6 +17,7 @@ namespace MCU { // Service commands void getBatteryLevel(u32 messagePointer); + void setInfoLEDPattern(u32 messagePointer); public: HWCService(Memory& mem, const EmulatorConfig& config) : mem(mem), config(config) {} diff --git a/readme.md b/readme.md index 35715ac23..7ffb7384f 100644 --- a/readme.md +++ b/readme.md @@ -19,14 +19,14 @@ SDL builds (No GUI): |Platform|Status|Download| |--------|------------|--------| |Windows build|[![Windows Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml)|[Windows Executable](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Windows_Build/master/Windows%20executable.zip)| -|MacOS build|[![MacOS Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/MacOS_Build/master/MacOS%20Alber%20App%20Bundle.zip)| +|MacOS build|[![MacOS Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/MacOS_Build/master/MacOS%20Alber%20App%20Bundle%20(universal).zip)| |Linux build|[![Linux Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml)|[Linux AppImage](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Linux_AppImage_Build/master/Linux%20executable.zip)| Qt and Android builds: |Platform|Status|Download| |--------|------------|--------| |Windows build|[![Qt Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml)|[Windows Executable](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Windows%20executable.zip)| -|MacOS build|[![Qt Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/MacOS%20Alber%20App%20Bundle.zip)| +|MacOS build|[![Qt Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/MacOS%20Alber%20App%20Bundle%20(universal).zip)| |Linux build|[![Qt Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml)|[Linux AppImage](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Linux%20executable.zip)| |Android build (arm64)|[![Android Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Android_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Android_Build.yml)|[Android APK](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Android_Build/master/Android%20APKs%20(arm64).zip)| @@ -118,7 +118,7 @@ Panda3DS also supports controller input using the SDL2 GameController API. - [ChonkyStation](https://github.com/liuk7071/ChonkyStation): Work-in-progress PlayStation emulator - [shadPS4](https://github.com/shadps4-emu/shadPS4): Work-in-progress PS4 emulator by the founder of PCSX, PCSX2 and more - [Hydra](https://github.com/hydra-emu/hydra): Cross-platform GameBoy, NES, N64 and Chip-8 emulator - +- [Tanuki3DS](https://github.com/burhanr13/Tanuki3DS/): A new 3DS emulator for MacOS and Linux # Support If you find this project exciting and want to support the founder, check out [his Patreon](https://www.patreon.com/wheremyfoodat) or [Ko-fi](https://ko-fi.com/wheremyfoodat)
diff --git a/src/config.cpp b/src/config.cpp index fd4d969d4..73b5d6644 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -141,6 +141,7 @@ void EmulatorConfig::load() { frontendSettings.theme = FrontendSettings::themeFromString(toml::find_or(ui, "Theme", "dark")); frontendSettings.icon = FrontendSettings::iconFromString(toml::find_or(ui, "WindowIcon", "rpog")); + frontendSettings.language = toml::find_or(ui, "Language", "en"); } } } @@ -202,6 +203,7 @@ void EmulatorConfig::save() { data["UI"]["Theme"] = std::string(FrontendSettings::themeToString(frontendSettings.theme)); data["UI"]["WindowIcon"] = std::string(FrontendSettings::iconToString(frontendSettings.icon)); + data["UI"]["Language"] = frontendSettings.language; std::ofstream file(path, std::ios::out); file << data; diff --git a/src/core/fs/archive_card_spi.cpp b/src/core/fs/archive_card_spi.cpp new file mode 100644 index 000000000..db1b5fded --- /dev/null +++ b/src/core/fs/archive_card_spi.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "fs/archive_card_spi.hpp" + +namespace fs = std::filesystem; + +HorizonResult CardSPIArchive::createFile(const FSPath& path, u64 size) { + Helpers::panic("[Card SPI] CreateFile not yet supported"); + return Result::Success; +} + +HorizonResult CardSPIArchive::deleteFile(const FSPath& path) { + Helpers::panic("[Card SPI] Unimplemented DeleteFile"); + return Result::Success; +} + +HorizonResult CardSPIArchive::createDirectory(const FSPath& path) { + Helpers::panic("[Card SPI] CreateDirectory not yet supported"); + return Result::Success; +} + +FileDescriptor CardSPIArchive::openFile(const FSPath& path, const FilePerms& perms) { + Helpers::panic("[Card SPI] OpenFile not yet supported"); + return FileError; +} + +Rust::Result CardSPIArchive::openArchive(const FSPath& path) { + if (path.type != PathType::Empty) { + Helpers::panic("Unimplemented path type for CardSPIArchive::OpenArchive"); + } + + Helpers::warn("Unimplemented: Card SPI archive"); + return Err(Result::FailurePlaceholder); +} + +Rust::Result CardSPIArchive::openDirectory(const FSPath& path) { + Helpers::panic("[Card SPI] OpenDirectory not yet supported"); + return Err(Result::FailurePlaceholder); +} diff --git a/src/core/fs/archive_system_save_data.cpp b/src/core/fs/archive_system_save_data.cpp index 37afb431f..7cb454a25 100644 --- a/src/core/fs/archive_system_save_data.cpp +++ b/src/core/fs/archive_system_save_data.cpp @@ -87,7 +87,7 @@ HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) { HorizonResult SystemSaveDataArchive::createDirectory(const FSPath& path) { if (path.type == PathType::UTF16) { if (!isPathSafe(path)) { - Helpers::panic("Unsafe path in SystemSaveData::OpenFile"); + Helpers::panic("Unsafe path in SystemSaveData::CreateDirectory"); } fs::path p = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData"; diff --git a/src/core/fs/archive_twl_photo.cpp b/src/core/fs/archive_twl_photo.cpp new file mode 100644 index 000000000..a1833c5cf --- /dev/null +++ b/src/core/fs/archive_twl_photo.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "fs/archive_twl_photo.hpp" + +namespace fs = std::filesystem; + +HorizonResult TWLPhotoArchive::createFile(const FSPath& path, u64 size) { + Helpers::panic("[TWL_PHOTO] CreateFile not yet supported"); + return Result::Success; +} + +HorizonResult TWLPhotoArchive::deleteFile(const FSPath& path) { + Helpers::panic("[TWL_PHOTO] Unimplemented DeleteFile"); + return Result::Success; +} + +HorizonResult TWLPhotoArchive::createDirectory(const FSPath& path) { + Helpers::panic("[TWL_PHOTO] CreateDirectory not yet supported"); + return Result::Success; +} + +FileDescriptor TWLPhotoArchive::openFile(const FSPath& path, const FilePerms& perms) { + Helpers::panic("[TWL_PHOTO] OpenFile not yet supported"); + return FileError; +} + +Rust::Result TWLPhotoArchive::openArchive(const FSPath& path) { + if (path.type != PathType::Empty) { + Helpers::panic("Unimplemented path type for TWLPhotoArchive::OpenArchive"); + } + + Helpers::warn("Unimplemented: TWL_PHOTO archive"); + return Err(Result::FailurePlaceholder); +} + +Rust::Result TWLPhotoArchive::openDirectory(const FSPath& path) { + Helpers::panic("[TWL_PHOTO] OpenDirectory not yet supported"); + return Err(Result::FailurePlaceholder); +} diff --git a/src/core/fs/archive_twl_sound.cpp b/src/core/fs/archive_twl_sound.cpp new file mode 100644 index 000000000..fbe98caf5 --- /dev/null +++ b/src/core/fs/archive_twl_sound.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "fs/archive_twl_sound.hpp" + +namespace fs = std::filesystem; + +HorizonResult TWLSoundArchive::createFile(const FSPath& path, u64 size) { + Helpers::panic("[TWL_SOUND] CreateFile not yet supported"); + return Result::Success; +} + +HorizonResult TWLSoundArchive::deleteFile(const FSPath& path) { + Helpers::panic("[TWL_SOUND] Unimplemented DeleteFile"); + return Result::Success; +} + +HorizonResult TWLSoundArchive::createDirectory(const FSPath& path) { + Helpers::panic("[TWL_SOUND] CreateDirectory not yet supported"); + return Result::Success; +} + +FileDescriptor TWLSoundArchive::openFile(const FSPath& path, const FilePerms& perms) { + Helpers::panic("[TWL_SOUND] OpenFile not yet supported"); + return FileError; +} + +Rust::Result TWLSoundArchive::openArchive(const FSPath& path) { + if (path.type != PathType::Empty) { + Helpers::panic("Unimplemented path type for TWLSoundArchive::OpenArchive"); + } + + Helpers::warn("Unimplemented: TWL_SOUND archive"); + return Err(Result::FailurePlaceholder); +} + +Rust::Result TWLSoundArchive::openDirectory(const FSPath& path) { + Helpers::panic("[TWL_SOUND] OpenDirectory not yet supported"); + return Err(Result::FailurePlaceholder); +} diff --git a/src/core/services/dsp.cpp b/src/core/services/dsp.cpp index 5d7956b51..93de78da1 100644 --- a/src/core/services/dsp.cpp +++ b/src/core/services/dsp.cpp @@ -28,7 +28,8 @@ namespace DSPCommands { RegisterInterruptEvents = 0x00150082, GetSemaphoreEventHandle = 0x00160000, SetSemaphoreMask = 0x00170040, - GetHeadphoneStatus = 0x001F0000 + GetHeadphoneStatus = 0x001F0000, + ForceHeadphoneOut = 0x00200040, }; } @@ -42,6 +43,7 @@ namespace Result { void DSPService::reset() { totalEventCount = 0; semaphoreMask = 0; + headphonesInserted = true; semaphoreEvent = std::nullopt; interrupt0 = std::nullopt; @@ -60,6 +62,7 @@ void DSPService::handleSyncRequest(u32 messagePointer) { case DSPCommands::ConvertProcessAddressFromDspDram: convertProcessAddressFromDspDram(messagePointer); break; case DSPCommands::FlushDataCache: flushDataCache(messagePointer); break; case DSPCommands::InvalidateDataCache: invalidateDCache(messagePointer); break; + case DSPCommands::ForceHeadphoneOut: forceHeadphoneOut(messagePointer); break; case DSPCommands::GetHeadphoneStatus: getHeadphoneStatus(messagePointer); break; case DSPCommands::GetSemaphoreEventHandle: getSemaphoreEventHandle(messagePointer); break; case DSPCommands::LoadComponent: loadComponent(messagePointer); break; @@ -210,7 +213,8 @@ void DSPService::getHeadphoneStatus(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x1F, 2, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, Result::HeadphonesInserted); // This should be toggleable for shits and giggles + // This should be toggleable for shits and giggles + mem.write32(messagePointer + 8, headphonesInserted ? Result::HeadphonesInserted : Result::HeadphonesNotInserted); } void DSPService::getSemaphoreEventHandle(u32 messagePointer) { @@ -278,6 +282,14 @@ void DSPService::invalidateDCache(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void DSPService::forceHeadphoneOut(u32 messagePointer) { + headphonesInserted = mem.read8(messagePointer + 4) != 0; + + log("DSP::ForceHeadphoneOut\n"); + mem.write32(messagePointer, IPC::responseHeader(0x20, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + DSPService::ComponentDumpResult DSPService::dumpComponent(const std::filesystem::path& path) { if (loadedComponent.empty()) { return ComponentDumpResult::NotLoaded; diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index e81db6cd3..54a4241dd 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -99,6 +99,11 @@ ArchiveBase* FSService::getArchiveFromID(u32 id, const FSPath& archivePath) { case ArchiveID::SDMC: return &sdmc; case ArchiveID::SDMCWriteOnly: return &sdmcWriteOnly; case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI + + case ArchiveID::TwlPhoto: return &twlPhoto; + case ArchiveID::TwlSound: return &twlSound; + case ArchiveID::CardSPI: return &cardSpi; + default: Helpers::panic("Unknown archive. ID: %d\n", id); return nullptr; diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 8cf77a7e5..96364e736 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -14,6 +14,7 @@ namespace ServiceCommands { WriteHwRegsWithMask = 0x00020084, SetBufferSwap = 0x00050200, FlushDataCache = 0x00080082, + InvalidateDataCache = 0x00090082, SetLCDForceBlack = 0x000B0040, TriggerCmdReqQueue = 0x000C0000, ReleaseRight = 0x00170000, @@ -21,7 +22,7 @@ namespace ServiceCommands { SaveVramSysArea = 0x00190000, RestoreVramSysArea = 0x001A0000, SetInternalPriorities = 0x001E0080, - StoreDataCache = 0x001F0082 + StoreDataCache = 0x001F0082, }; } @@ -63,6 +64,7 @@ void GPUService::handleSyncRequest(u32 messagePointer) { case ServiceCommands::ReadHwRegs: readHwRegs(messagePointer); break; case ServiceCommands::WriteHwRegs: writeHwRegs(messagePointer); break; case ServiceCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break; + case ServiceCommands::InvalidateDataCache: invalidateDataCache(messagePointer); break; default: Helpers::panic("GPU service requested. Command: %08X\n", command); } } @@ -278,6 +280,16 @@ void GPUService::flushDataCache(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void GPUService::invalidateDataCache(u32 messagePointer) { + u32 address = mem.read32(messagePointer + 4); + u32 size = mem.read32(messagePointer + 8); + u32 processHandle = handle = mem.read32(messagePointer + 16); + log("GSP::GPU::InvalidateDataCache(address = %08X, size = %X, process = %X)\n", address, size, processHandle); + + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void GPUService::storeDataCache(u32 messagePointer) { u32 address = mem.read32(messagePointer + 4); u32 size = mem.read32(messagePointer + 8); diff --git a/src/core/services/mcu/mcu_hwc.cpp b/src/core/services/mcu/mcu_hwc.cpp index 2873adf5c..0e4e6ed35 100644 --- a/src/core/services/mcu/mcu_hwc.cpp +++ b/src/core/services/mcu/mcu_hwc.cpp @@ -1,10 +1,12 @@ +#include "services/mcu/mcu_hwc.hpp" + #include "ipc.hpp" #include "result/result.hpp" -#include "services/mcu/mcu_hwc.hpp" namespace MCU::HWCCommands { enum : u32 { GetBatteryLevel = 0x00050000, + SetInfoLedPattern = 0x000A0640, }; } @@ -14,6 +16,7 @@ void MCU::HWCService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { case HWCCommands::GetBatteryLevel: getBatteryLevel(messagePointer); break; + case HWCCommands::SetInfoLedPattern: setInfoLEDPattern(messagePointer); break; default: Helpers::panic("MCU::HWC service requested. Command: %08X\n", command); } } @@ -24,4 +27,12 @@ void MCU::HWCService::getBatteryLevel(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x5, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, config.batteryPercentage); +} + +void MCU::HWCService::setInfoLEDPattern(u32 messagePointer) { + log("MCU::HWC::SetInfoLedPattern\n"); + + // 25 parameters to make some notification LEDs blink... + mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index ac9007550..84b638f3f 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -428,6 +428,10 @@ RomFS::DumpingResult Emulator::dumpRomFS(const std::filesystem::path& path) { } void Emulator::setAudioEnabled(bool enable) { + // Don't enable audio if we didn't manage to find an audio device and initialize it properly, otherwise audio sync will break, + // because the emulator will expect the audio device to drain the sample buffer, but there's no audio device running... + enable = enable && audioDevice.isInitialized(); + if (!enable) { audioDevice.stop(); } else if (enable && romType != ROMType::None && running) { diff --git a/src/panda_qt/config_window.cpp b/src/panda_qt/config_window.cpp index 7f42acab9..519a4a227 100644 --- a/src/panda_qt/config_window.cpp +++ b/src/panda_qt/config_window.cpp @@ -12,7 +12,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win // Set the window title of the main window appropriately if we enable showing the app version on the window if (config.windowSettings.showAppVersion) { - getMainWindow()->setWindowTitle("Alber v" PANDA3DS_VERSION); + getMainWindow()->setWindowTitle(tr("Alber v%1").arg(PANDA3DS_VERSION)); } // Initialize the widget list and the widget container widgets @@ -96,6 +96,9 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win }); guiLayout->addRow(tr("Window icon"), iconSelect); + QComboBox* languageSelect = createLanguageSelect(); + guiLayout->addRow(tr("Language"), languageSelect); + QCheckBox* showAppVersion = new QCheckBox(tr("Show version on window title")); showAppVersion->setChecked(config.windowSettings.showAppVersion); connect(showAppVersion, &QCheckBox::toggled, this, [&](bool checked) { @@ -103,7 +106,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win updateConfig(); // Update main window title - getMainWindow()->setWindowTitle(checked ? "Alber v" PANDA3DS_VERSION : "Alber"); + getMainWindow()->setWindowTitle(checked ? tr("Alber v%1").arg(PANDA3DS_VERSION) : tr("Alber")); }); connectCheckbox(showAppVersion, config.windowSettings.showAppVersion); guiLayout->addRow(showAppVersion); diff --git a/src/panda_qt/main_window.cpp b/src/panda_qt/main_window.cpp index 5af31d737..c30d23ca2 100644 --- a/src/panda_qt/main_window.cpp +++ b/src/panda_qt/main_window.cpp @@ -14,6 +14,9 @@ #include "version.hpp" MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent), keyboardMappings(InputMappings::defaultKeyboardMappings()) { + emu = new Emulator(); + + loadTranslation(); setWindowTitle(tr("Alber")); // Enable drop events for loading ROMs @@ -28,8 +31,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) appRunning = true; // Set our menu bar up - menuBar = new QMenuBar(this); - setMenuBar(menuBar); + menuBar = new QMenuBar(nullptr); // Create menu bar menus auto fileMenu = menuBar->addMenu(tr("File")); @@ -74,8 +76,8 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) auto aboutAction = aboutMenu->addAction(tr("About Panda3DS")); connect(aboutAction, &QAction::triggered, this, &MainWindow::showAboutMenu); + setMenuBar(menuBar); - emu = new Emulator(); emu->setOutputSize(screen->surfaceWidth, screen->surfaceHeight); // Set up misc objects @@ -678,4 +680,4 @@ void MainWindow::setupControllerSensors(SDL_GameController* controller) { if (haveAccelerometer) { SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); } -} +} \ No newline at end of file diff --git a/src/panda_qt/translations.cpp b/src/panda_qt/translations.cpp new file mode 100644 index 000000000..bfadd5700 --- /dev/null +++ b/src/panda_qt/translations.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#include "panda_qt/config_window.hpp" +#include "panda_qt/main_window.hpp" + +void MainWindow::loadTranslation() { + // TODO: This should become a member variable when we allow changing language at runtime. + QTranslator* translator = nullptr; + + // Fetch the .qm file for our language and load it + auto language = QString::fromStdString(emu->getConfig().frontendSettings.language); + const QString baseDir = QStringLiteral(":/translations"); + const QString basePath = QStringLiteral("%1/%2.qm").arg(baseDir).arg(language); + + if (QFile::exists(basePath)) { + if (translator != nullptr) { + qApp->removeTranslator(translator); + } + + translator = new QTranslator(qApp); + if (!translator->load(basePath)) { + QMessageBox::warning( + nullptr, QStringLiteral("Translation Error"), + QStringLiteral("Failed to find load translation file for '%1':\n%2").arg(language).arg(basePath) + ); + delete translator; + } else { + qApp->installTranslator(translator); + } + } else { + printf("Language file %s does not exist. Defaulting to English\n", basePath.toStdString().c_str()); + } +} + +struct LanguageInfo { + QString name; // Full name of the language (for example "English (US)") + const char* code; // ISO 639 language code (for example "en_us") + + explicit LanguageInfo(const QString& name, const char* code) : name(name), code(code) {} +}; + +// List of languages in the order they should appear in the menu +// Please keep this list mostly in alphabetical order. +// Also, for Unicode characters in language names, use Unicode keycodes instead of writing out the name, +// as some compilers/toolchains may not enjoy Unicode in source files. +static std::array languages = { + LanguageInfo(QStringLiteral(u"English"), "en"), // English + LanguageInfo(QStringLiteral(u"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"), "el"), // Greek + LanguageInfo(QStringLiteral(u"Espa\u00F1ol"), "es"), // Spanish + LanguageInfo(QStringLiteral(u"Nederlands"), "nl"), // Dutch + LanguageInfo(QStringLiteral(u"Portugu\u00EAs (Brasil)"), "pt_br") // Portuguese (Brazilian) +}; + +QComboBox* ConfigWindow::createLanguageSelect() { + QComboBox* select = new QComboBox(); + + for (usize i = 0; i < languages.size(); i++) { + const auto& lang = languages[i]; + select->addItem(lang.name); + + if (config.frontendSettings.language == lang.code) { + select->setCurrentIndex(i); + } + } + + connect(select, &QComboBox::currentIndexChanged, this, [&](int index) { + const QString baseDir = QStringLiteral(":/translations"); + const QString basePath = QStringLiteral("%1/%2.qm").arg(baseDir).arg(languages[index].code); + + if (QFile::exists(basePath)) { + config.frontendSettings.language = languages[index].code; + updateConfig(); + + QMessageBox messageBox( + QMessageBox::Icon::Information, tr("Language change successful"), + tr("Restart Panda3DS for the new language to be used.") + ); + + messageBox.exec(); + } else { + QMessageBox messageBox( + QMessageBox::Icon::Warning, tr("Language change failed"), + tr("The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code...") + ); + + messageBox.exec(); + } + }); + + return select; +} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index 503684acc..c6764d382 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -152,6 +152,10 @@ protected void onPause() { @Override public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) { + return super.dispatchKeyEvent(event); + } + if ((!drawerFragment.isOpened()) && InputHandler.processKeyEvent(event)) { return true; } diff --git a/third_party/LuaJIT b/third_party/LuaJIT index 41edf0959..8bf7686d8 160000 --- a/third_party/LuaJIT +++ b/third_party/LuaJIT @@ -1 +1 @@ -Subproject commit 41edf0959b9504d36dd85f5f16893c004ea7d7ba +Subproject commit 8bf7686d820f868eae1a522c481fee09c18c90b9 diff --git a/third_party/oaknut b/third_party/oaknut index 94c726ce0..790374d7e 160000 --- a/third_party/oaknut +++ b/third_party/oaknut @@ -1 +1 @@ -Subproject commit 94c726ce0338b054eb8cb5ea91de8fe6c19f4392 +Subproject commit 790374d7e66257b1f8ed89d798e5dcfb5363af05