Compare commits

...
226 Commits
Author SHA1 Message Date
Rosalie Wanders 3707a86c79 Package: v0.3.2 2023-02-06 22:23:53 +01:00
Rosalie Wanders eea3ec7f95 RMG-Input: load SDL_GameControllerDB 2023-02-06 16:01:15 +01:00
Rosalie Wanders 4a2c6761fc cmake: install SDL_GameControllerDB 2023-02-06 16:01:15 +01:00
Rosalie Wanders 7a4e179f4c 3rdParty: add SDL_GameControllerDB 2023-02-06 16:01:15 +01:00
Rosalie Wanders 11eaadb739 RMG: use RomBrowser_SortAfterSearch setting 2023-02-05 20:29:40 +01:00
Rosalie Wanders 41b77b54ea RMG-Core: add RomBrowser_SortAfterSearch setting 2023-02-05 20:29:11 +01:00
Rosalie Wanders 22689bd9ee 3rdParty: update mupen64plus-core 2023-02-05 20:02:39 +01:00
Rosalie Wanders 831535c86f RMG-Core: remove Input_InvertAxis setting 2023-02-05 20:02:25 +01:00
Rosalie Wanders ce43955784 RMG-Input: remove 'Invert Axis Mapped To LRZ' 2023-02-05 20:02:25 +01:00
Rosalie Wanders e85f4f4309 RMG-Input: filter SDL events based on joystick type 2023-02-05 20:02:25 +01:00
Rosalie Wanders 00b3f33530 RMG-Core: use extracted_file.filename() in CoreOpenRom() 2023-02-04 23:18:47 +01:00
Rosalie Wanders 1b0116a0cb RMG-Core: don't use OSAL_FILES_DIR_SEPERATOR_STR in CoreOpenRom() 2023-02-04 23:14:45 +01:00
Rosalie Wanders 486281427c Package: v0.3.1 2023-02-04 22:40:11 +01:00
Rosalie Wanders 8ccdc415bc RMG-Input: implement support for mapping multiple inputs 2023-02-04 22:28:37 +01:00
Rosalie Wanders 008049265d RMG-Core: don't add list separator at end of the list in settings 2023-02-04 22:10:48 +01:00
Rosalie Wanders fef407b839 RMG-Core: implement string list settings functions 2023-02-04 17:22:26 +01:00
Rosalie Wanders 084570bc4b 3rdParty: update mupen64plus-core 2023-02-04 14:43:45 +01:00
Rosalie Wanders 3d91e0c3e3 3rdParty: update GLideN64 2023-02-04 14:39:34 +01:00
Rosalie Wanders b5a942b4fe RMG: retrieve fallbackTheme before applying application theme 2023-02-02 22:28:37 +01:00
Rosalie Wanders 5c5cc8453d RMG: correct remove duplicate keybindings in SettingsDialog 2023-02-02 21:48:33 +01:00
Rosalie Wanders 30495795cd RMG: account for 'Refresh ROM List' in SettingsDialog::commonHotkeySettings() 2023-02-02 21:47:57 +01:00
Rosalie Wanders 073cdd2815 RMG: remove unneeded mutex in SettingsDialog.hpp 2023-02-02 21:30:04 +01:00
Rosalie Wanders fe21c73f75 RMG: improve hotkey button behavior in SettingsDialog 2023-02-02 21:28:44 +01:00
Rosalie Wanders a6cba2ce2a RMG: account for filenames without a dot in RomBrowserWidget::getCurrentCover() 2023-02-02 21:21:59 +01:00
Rosalie Wanders 9afd971b43 RMG: correct basename in RomBrowserWidget::getCurrentCover() 2023-02-02 21:20:21 +01:00
Rosalie Wanders b0f9136fe8 RMG: skip empty names in RomBrowserWidget::getCurrentCover() 2023-02-02 12:57:58 +01:00
Rosalie Wanders b513439565 RMG: support base name of ROM file for covers 2023-02-02 12:57:37 +01:00
Rosalie Wanders 42494e5019 RMG: show emulation error message after switching back to the ROM browser 2023-02-01 20:55:53 +01:00
Rosalie Wanders 8653234cb3 RMG: don't switch to the ROM browser when launching a ROM from the commandline 2023-02-01 20:55:29 +01:00
Rosalie Wanders 6a14761770 RMG-Core: implement support for ndd/d64 files in zip files 2023-02-01 20:39:07 +01:00
Rosalie Wanders 399a5c93b2 RMG-Core: introduce & use CoreResetMediaLoader() 2023-02-01 19:43:59 +01:00
Rosalie Wanders be2db3c95a 3rdParty: update mupen64plus-core 2023-01-31 21:59:00 +01:00
Rosalie Wanders 7f7ac4c5fb 3rdParty: update mupen64plus-core 2023-01-24 16:24:33 +01:00
Rosalie Wanders 7ca98bb496 3rdParty: use ${IMGUI_BUILD_DIR} instead of ${IMGUI_DIR}/build 2023-01-24 15:39:32 +01:00
Rosalie Wanders e9cf27411b RMG: shutdown OSD before moving OpenGL context back to GUI thread 2023-01-24 15:17:14 +01:00
Rosalie Wanders d8f1a5a118 Package: v0.3.0 2023-01-23 22:50:18 +01:00
Rosalie Wanders 07ea2d8ec4 RMG: reset OSD message in OnScreenDisplayShutdown() 2023-01-23 22:43:24 +01:00
Rosalie Wanders 2c63963134 3rdParty: create imgui build directory in CONFIGURE_COMMAND 2023-01-23 22:43:24 +01:00
Rosalie Wanders c9d9e71631 RMG: std::ceil() when accounting for HiDPI scaling in on_VidExt_ResizeWindow 2023-01-22 18:50:06 +01:00
Rosalie Wanders 69726baa48 Script: add --no-translations to windeployqt-qt6 in BundleDependencies.sh 2023-01-22 14:15:46 +01:00
Rosalie Wanders c02a44d020 RMG: fix build failure on windows 2023-01-22 14:04:27 +01:00
Rosalie Wanders 1c0c3eb6aa Script: remove DownloadStyles.sh 2023-01-22 13:53:32 +01:00
Rosalie Wanders 7f9f30181e ci: remove usage of DownloadStyles.sh 2023-01-22 13:53:23 +01:00
Rosalie Wanders 2bc788beea RMG: expose & use GUI_Theme setting 2023-01-22 13:52:30 +01:00
Rosalie Wanders 4a0d20c1a1 RMG-Core: remove GUI_{Style,IconTheme} settings & add GUI_Theme setting 2023-01-22 13:51:36 +01:00
Rosalie Wanders 2ea9efd622 RMG: change tab order of SettingsDialog 2023-01-22 13:30:49 +01:00
Rosalie Wanders 723f4ab16b cmake: remove USE_QT5 option 2023-01-22 13:30:02 +01:00
Rosalie Wanders a242ae78eb RMG-Core: remove GUI_AllowManualResizing setting 2023-01-22 13:04:28 +01:00
Rosalie Wanders c037e1465f RMG: remove usage of GUI_AllowManualResizing setting 2023-01-22 13:04:21 +01:00
Rosalie Wanders 3e8578f2fd RMG: store & load maximized state 2023-01-22 12:51:14 +01:00
Rosalie Wanders 0050646ad7 RMG-Core: add RomBrowser_Maximized setting 2023-01-22 12:51:00 +01:00
Rosalie Wanders f2ef7e345f RMG-Core: improve error message in read_zip_file 2023-01-21 16:01:05 +01:00
Rosalie Wanders 3c0698d14b RMG-Core: open std::ifstream with std::ios::binary in Rom.cpp 2023-01-21 15:26:09 +01:00
Rosalie Wanders ec677c8d26 RMG-Core: implement zlib file functions 2023-01-21 14:53:22 +01:00
Rosalie Wanders f115c82512 RMG: expose & use GUI_OnScreenDisplayDuration setting 2023-01-19 15:24:58 +01:00
Rosalie Wanders 9f4f8ab15b RMG-Core: add GUI_OnScreenDisplayDuration setting 2023-01-19 15:24:39 +01:00
Rosalie Wanders 532d8bcaee RMG: prevent imgui.ini from being created 2023-01-19 15:08:22 +01:00
Rosalie Wanders 2978b8443c RMG: expose & use GUI_OnScreenDisplayOpacity setting 2023-01-19 15:03:59 +01:00
Rosalie Wanders 3b1fbcd9d3 RMG-Core: add GUI_OnScreenDisplayOpacity setting 2023-01-19 15:03:43 +01:00
Rosalie Wanders de4d4c27c7 RMG-Core: fix M64TYPE_FLOAT not behaving correctly 2023-01-19 15:03:30 +01:00
Rosalie Wanders 91bf6ad996 RMG: show toolbar when it's hidden in loadGeometry() 2023-01-19 14:27:03 +01:00
Rosalie Wanders 312885bec1 RMG: remove unneeded includes in VidExt.cpp 2023-01-19 14:01:10 +01:00
Rosalie Wanders 8641e1b3ba RMG: introduce OSD 2023-01-19 13:58:20 +01:00
Rosalie Wanders ca203d96b0 RMG-Core: add OSD settings 2023-01-19 13:52:17 +01:00
Rosalie Wanders 6774c8731a 3rdParty: add imgui 2023-01-19 13:52:10 +01:00
Rosalie Wanders b603f3b75c gitignore: add compile_commands.json 2023-01-19 13:47:07 +01:00
Rosalie Wanders b546826b67 gitignore: add ArchLinux package 2023-01-19 13:47:04 +01:00
Rosalie Wanders a39263aeb5 3rdParty: update GLideN64 2023-01-19 12:33:11 +01:00
Rosalie Wanders ecaa5b9dee 3rdParty: update mupen64plus-core 2023-01-19 12:32:47 +01:00
RosalieandGitHub 7fcc468353 Script: update openssl libs in BundleDependencies.sh 2023-01-18 23:47:35 +01:00
porcinoandGitHub 52952942e9 RMG-Input: correct simulate_deadzone (#86) 2023-01-18 23:31:26 +01:00
Rosalie Wanders 81dc449637 RMG-Input: force refresh deadzone label value 2023-01-18 21:04:37 +01:00
Rosalie Wanders ce25524ed9 README: update to reflect build changes 2023-01-18 20:59:52 +01:00
Rosalie Wanders 30a3522def Script: remove unused scripts 2023-01-18 20:59:35 +01:00
Rosalie Wanders f62de70aa5 Package: update archlinux PKGBUILD 2023-01-18 20:47:29 +01:00
Rosalie Wanders ec190adc51 Script: remove pushd & popd from Build.sh 2023-01-18 20:31:58 +01:00
Rosalie Wanders 7095824874 ci: install ninja 2023-01-18 20:31:46 +01:00
Rosalie Wanders b243f48fff Script: copy dependencies for core lib in BundleDependencies.sh 2023-01-18 20:31:46 +01:00
Rosalie Wanders 3bc052e948 Script: use Ninja in Build.sh & use cmake --build & cmake --install 2023-01-18 20:31:46 +01:00
Rosalie Wanders 482e237d08 cmake: prepend bash to bundle_dependencies target command 2023-01-18 20:31:46 +01:00
Rosalie Wanders 86f38ab024 3rdParty: use make instead of $(MAKE) 2023-01-18 20:31:46 +01:00
Rosalie Wanders c837d736bb 3rdParty: update mupen64plus-video-parallel 2023-01-10 21:53:43 +01:00
Rosalie Wanders ab94fd484f 3rdParty: update mupen64plus-core 2023-01-10 21:53:36 +01:00
Rosalie Wanders 1508b11044 3rdParty: update mupen64plus-core 2023-01-06 21:40:52 +01:00
Rosalie Wanders b4e18d1b63 RMG: add save state slot keybindings in addFullscreenActions() 2023-01-05 12:26:32 +01:00
Rosalie Wanders f49272288d RMG: correct QUrl in RomBrowserWidget.cpp 2023-01-04 21:36:20 +01:00
Rosalie Wanders f1dd82c65e README: update dependencies 2023-01-04 21:25:16 +01:00
Rosalie Wanders 7aa7eaffb9 ci: remove unrequired msys2 packages 2023-01-04 21:10:48 +01:00
Rosalie Wanders 6577fa9810 RMG: correct QUrl in on_Action_OpenRomDirectory() 2023-01-04 15:00:06 +01:00
Rosalie Wanders 6aabc4eca8 RMG: add 'Open ROM Directory' to ROM Browser 2023-01-04 14:55:20 +01:00
Rosalie Wanders bf5b3d3c99 RMG: add 'Play Game with Cartridge" when a disk is selected 2023-01-04 14:45:15 +01:00
Rosalie Wanders 420eb39c16 RMG-Core: store CoreRomType in RomHeaderAndSettings cache 2023-01-04 14:43:54 +01:00
Rosalie Wanders 6dd764c04c 3rdParty: fix make clean not working correctly 2023-01-04 14:12:42 +01:00
Rosalie Wanders 95d5141a2b 3rdParty: update GLideN64 2023-01-04 13:50:39 +01:00
RosalieandGitHub 51c6c3904d README: add some screenshots 2023-01-04 11:01:23 +01:00
Rosalie Wanders 32a39afc75 Package: v0.2.9 2023-01-03 19:09:35 +01:00
Rosalie Wanders fd967cc2a3 RMG: correct commonInterfaceStyleSettings() in SettingsDialog 2023-01-03 18:39:51 +01:00
Rosalie Wanders 8c0bb09667 RMG: improve behavior of Hotkeys tab in SettingsDialog 2023-01-03 18:28:38 +01:00
Rosalie Wanders 8c753d6cfe RMG: add 'Current Save State' tab to Hotkeys tab in SettingsDialog 2023-01-03 18:02:40 +01:00
Rosalie Wanders 276e681f29 RMG-Core: add save state slot keybinding settings 2023-01-03 18:00:48 +01:00
Rosalie Wanders f23b17e1b8 RMG: "Choose ROM Directory" -> "Change ROM Directory" 2023-01-03 17:39:47 +01:00
Rosalie Wanders f1e10fa4b1 RMG: add icon for 'Current Save State' & 'GS Button' 2023-01-03 17:39:20 +01:00
Rosalie Wanders be67cd03cb RMG-Core: correct CORE_INSTALL_PREFIX name 2023-01-03 16:37:42 +01:00
Rosalie Wanders d7dfe12fb4 RMG: don't use setCurrentIndex() in MainWindow.cpp 2023-01-03 16:25:53 +01:00
Rosalie Wanders be437afd2f RMG: save geomtry in closeEvent() when emulation isn't running 2023-01-03 16:10:26 +01:00
Rosalie Wanders f72688773a RMG: don't switch back to ROM browser in closeEvent() 2023-01-03 15:07:44 +01:00
Rosalie Wanders fb328d8d92 RMG: install qt message handler 2023-01-03 14:40:51 +01:00
Rosalie Wanders 36e6d2fcc7 RMG: add -q/--quit-after-emulation commandline option 2023-01-03 13:57:08 +01:00
Rosalie Wanders 7b3293341b RMG: check visibility of OGLWidget in VidExt_OglSetup() 2023-01-03 13:50:57 +01:00
Rosalie Wanders 0a7b72a51b RMG: only set current directory in when PORTABLE_INSTALL is defined 2023-01-03 13:10:19 +01:00
Rosalie Wanders 6265973cc6 RMG-Core: use std::filesystem::path in osal_dynlib functions 2023-01-03 13:06:48 +01:00
Rosalie Wanders f1edc47a80 RMG-Core: correct osal_files_get_file_time for Windows 2023-01-03 12:53:06 +01:00
Rosalie Wanders 8f60d5c80f RMG-Core: only free buffer when opening a cartridge 2023-01-02 12:54:19 +01:00
Rosalie Wanders c42489fa81 RMG: correct 64DD disk file extension in RomBrowserEmptyWidget 2023-01-02 00:07:39 +01:00
Rosalie Wanders 66b60c988a RMG: update copyright year in AboutDialog 2023-01-02 00:04:22 +01:00
Rosalie Wanders 5d20e98aba Package: v0.2.8 2023-01-01 13:55:11 +01:00
Rosalie Wanders 617ee3f96c RMG: only call on_VidExt_ResizeWindow when not returning from fullscreen 2023-01-01 13:36:48 +01:00
Rosalie Wanders 083f7c2e4f RMG: simplify vidext function implementation 2023-01-01 13:14:07 +01:00
Rosalie Wanders a8ea1795bf Script: simplify BundleDependencies.sh 2023-01-01 12:43:49 +01:00
Rosalie Wanders 8a6cb4b5a8 RMG: configure toolbar & statusbar visibility in configureUI 2022-12-31 14:17:52 +01:00
Rosalie Wanders 53edf065a5 RMG: don't return when over the item limit in RomSearcherThread 2022-12-31 14:17:52 +01:00
Rosalie Wanders bf65be483d RMG: set current view widget in RomBrowserWidget constructor 2022-12-31 13:22:02 +01:00
Rosalie Wanders 1e90047368 3rdParty: use CMAKE_CONFIGURE_ARGS for mupen64plus-rsp-parallel 2022-12-30 14:24:07 +01:00
Rosalie Wanders abd1160f87 RMG: disable 'Uniform Size (Grid View)' during emulation 2022-12-29 01:34:49 +01:00
Rosalie Wanders 55d7dd9d89 RMG-Core: improve error message in read_raw_file 2022-12-29 01:18:58 +01:00
Rosalie Wanders b7eb1afb86 Package: v0.2.7 2022-12-29 00:28:43 +01:00
Rosalie Wanders 25ddb4a531 RMG: only refresh ROM list in SetGridViewUniformSizes when in grid view 2022-12-29 00:17:44 +01:00
Rosalie Wanders 79f7c2224b RMG: enable smooth scrolling in RomBrowserWidget 2022-12-29 00:14:58 +01:00
Rosalie Wanders 8adda4fc7d RMG: add more icons to the View menu 2022-12-29 00:14:38 +01:00
Rosalie Wanders 5d23743133 RMG: add 'Uniform Size (Grid View)' to View menu 2022-12-29 00:14:03 +01:00
Rosalie Wanders 2558e5d6a6 RMG-Core: add RomBrowser_GridViewUniformItemSizes setting 2022-12-29 00:08:49 +01:00
Rosalie Wanders 859b81b7e0 RMG: fixup cover filename in RomBrowserWidget 2022-12-28 23:09:46 +01:00
Rosalie Wanders 30369f58a9 3rdParty: update mupen64plus-core 2022-12-28 17:47:04 +01:00
Rosalie Wanders 30afc80a64 3rdParty: update mupen64plus-core 2022-12-28 17:23:32 +01:00
Rosalie Wanders 949eee8d08 RMG: improve updater script on windows 2022-12-28 16:34:40 +01:00
Rosalie Wanders 1fae30bd33 Script: also bundle libjpeg-8.dll for windows in BundleDependencies.sh 2022-12-28 16:18:59 +01:00
Rosalie Wanders d8817bf0f3 RMG: add disk files to RomBrowserEmptyWidget 2022-12-28 01:00:31 +01:00
Rosalie Wanders 5279b10b67 RMG: show core error even when statusbar is disabled 2022-12-28 00:36:21 +01:00
Rosalie Wanders 391f46be22 Package: update screenshots 2022-12-28 00:16:21 +01:00
Rosalie Wanders 44809bf28f Package: v0.2.6 2022-12-28 00:12:09 +01:00
Rosalie Wanders 3cd113c46f RMG: show context menu even when not having a selection 2022-12-28 00:10:56 +01:00
Rosalie Wanders 3d195c6a4d RMG: overhaul UI 2022-12-27 23:54:54 +01:00
Rosalie Wanders 423d30ac29 RMG-Core: introduce CoreClearRomHeaderAndSettingsCache() 2022-12-27 23:26:42 +01:00
Rosalie Wanders b07b73e005 RMG-Core: implement support for M64CMD_DISK_OPEN & M64CMD_DISK_CLOSE 2022-12-27 23:26:40 +01:00
Rosalie Wanders 418d9c4684 3rdParty: update mupen64plus-core 2022-12-27 23:26:38 +01:00
Rosalie Wanders 1801a48eaa 3rdParty: update GLideN64 2022-12-27 23:26:36 +01:00
Rosalie Wanders 8e8fbcdd2e Package: update archlinux PKGBUILD 2022-12-27 23:26:19 +01:00
Rosalie Wanders d5834de5e7 RMG-Input: disable Input_RemoveDuplicateMappings on linux 2022-12-27 23:25:53 +01:00
Rosalie Wanders a52e3fe1e5 RMG-Core: add more GUI settings 2022-12-19 21:07:45 +01:00
Rosalie Wanders eb261bc2bf RMG-Core: fix default save state/game directory being wrong 2022-12-19 21:07:45 +01:00
Rosalie Wanders 7b5f735714 RMG-Core: move over cheat settings in CoreUpdateCheat() 2022-12-19 13:27:10 +01:00
Rosalie Wanders 404c2c4f43 RMG: return M64ERR_UNSUPPORTED in VidExt_List{Modes,Rates} 2022-12-19 13:27:07 +01:00
Rosalie Wanders 57f1a33e51 3rdParty: update GLideN64 2022-12-19 13:27:05 +01:00
Rosalie Wanders fa277352b0 3rdParty: update angrylion-rdp-plus 2022-12-19 13:27:02 +01:00
Rosalie Wanders f502984e05 3rdParty: use $(MAKE) instead of make 2022-12-19 13:26:56 +01:00
Rosalie Wanders c205b5bfd3 3rdParty: update mupen64plus-video-parallel 2022-12-15 18:35:38 +01:00
Rosalie Wanders c6625e137d Package: v0.2.5 2022-12-14 20:46:09 +01:00
Rosalie Wanders 0ad7e1d715 Package: update & add screenshots 2022-12-14 20:38:45 +01:00
Rosalie Wanders 1f8d5be9a7 Package: update ArchLinux PKGBUILD 2022-12-14 20:30:12 +01:00
Rosalie Wanders 21673affbb RMG-Core: include Config.hpp in Directories.cpp 2022-12-14 20:28:11 +01:00
Rosalie Wanders a0a1255ef3 3rdParty: update mupen64plus-video-parallel 2022-12-14 20:16:26 +01:00
Rosalie Wanders 206a5ec7f6 3rdParty: update mupen64plus-video-angrylion-plus 2022-12-14 20:16:18 +01:00
Rosalie Wanders 8661273568 Script: update DownloadStyles.sh 2022-12-14 19:49:16 +01:00
Rosalie Wanders 6aed340831 RMG: call CoreGetVersion() in main.cpp 2022-12-14 19:13:38 +01:00
Rosalie Wanders f7bfb6aea1 RMG: remove Config.hpp include from main.cpp 2022-12-14 19:10:22 +01:00
Rosalie Wanders c5ae117cf8 RMG: remove Config.hpp include in RomBrowserWidget 2022-12-14 18:56:26 +01:00
Rosalie Wanders a1c9dc3f12 RMG: slightly redesign RomInfoDialog 2022-12-14 18:54:59 +01:00
Rosalie Wanders 0f3e70706d RMG-Input: allow removing/resetting the main profile 2022-12-14 18:50:55 +01:00
Rosalie Wanders 722ca67b87 RMG-Input: enable close button on all dialogs 2022-12-14 18:41:34 +01:00
Rosalie Wanders 981897df8c RMG-Audio: enable close button on all dialogs 2022-12-14 18:41:28 +01:00
Rosalie Wanders 3a066dfc03 RMG: enable close button on all dialogs 2022-12-14 18:41:06 +01:00
Rosalie Wanders 870481e34e Data: remove stylesheet.qss 2022-12-14 18:27:23 +01:00
Rosalie Wanders 9f5f2334d7 RMG: remove Config.hpp & use CoreGetVersion() 2022-12-14 18:26:30 +01:00
Rosalie Wanders 330a66c81c RMG-Core: introduce & use CoreGetVersion() 2022-12-14 18:26:01 +01:00
Rosalie Wanders 92b4d4dc32 RMG: remove 'About' button in plugins tab in SettingsDialog 2022-12-14 18:15:31 +01:00
Rosalie Wanders 531fab51be RMG: add correct info layouts to User Interface tab in SettingsDialog 2022-12-14 00:21:14 +01:00
Rosalie Wanders 3f027fad63 RMG-Input: force call on_controllerPluggedCheckBox_toggled() 2022-12-14 00:13:35 +01:00
Rosalie Wanders 6eb46dd63c RMG: also load misc settings tab in SettingsDialog 2022-12-13 23:53:58 +01:00
Rosalie Wanders 70830ae016 RMG-Input: do nothing in CheckInputDeviceSettings() when combobox is empty 2022-12-13 23:31:56 +01:00
Rosalie Wanders 8a88a736ad RMG-Input: actually add required svg resource 2022-12-13 23:02:39 +01:00
Rosalie Wanders d580d2be9a RMG-Input: add Z-Trigger to the svg & hook it up to ControllerImageWidget 2022-12-13 22:53:03 +01:00
Rosalie Wanders 0e3fc0e981 RMG: fix empty style setting 2022-12-13 21:57:47 +01:00
Rosalie Wanders 4907b2dd32 RMG: use fallback stylesheet 2022-12-13 21:57:44 +01:00
Rosalie Wanders 3ad2a5760e RMG: make ui_Stylesheet_Setup windows exclusive 2022-12-13 21:42:53 +01:00
Rosalie Wanders e474a09642 ci: execute DownloadStyles.sh on windows 2022-12-13 21:38:07 +01:00
Rosalie Wanders f5296c9f79 RMG: add style setting to SettingsDialog 2022-12-13 21:37:52 +01:00
Rosalie Wanders f8e1ed3920 RMG-Core: add GUI_Style setting 2022-12-13 21:33:01 +01:00
Rosalie Wanders 9aeca88946 Script: add DownloadStyles.sh 2022-12-13 21:32:43 +01:00
Rosalie Wanders 3961c066be ci: specify key for ccache-action 2022-12-13 16:11:32 +01:00
Rosalie Wanders 4aeb3da6eb cmake: respect C/C++ compiler in 3rdParty projects 2022-12-13 15:40:50 +01:00
Rosalie Wanders bf9e370ddd ci: use ccache 2022-12-13 15:26:29 +01:00
Rosalie Wanders 7c72fa98fd cmake: add USE_CCACHE option 2022-12-13 15:25:25 +01:00
Rosalie Wanders 0824586db9 RMG: remove Debugger checkbox from SettingsDialog 2022-12-13 14:51:56 +01:00
Rosalie Wanders 8a22c6d929 RMG: rename Interface tab to User Interface in SettingsDialog 2022-12-13 14:50:58 +01:00
Rosalie Wanders 8f76619d7d cmake: add USE_QT5 option 2022-12-13 13:48:15 +01:00
Rosalie Wanders d94d9fc5d7 3rdParty: update GLideN64 2022-12-12 21:58:27 +01:00
Rosalie Wanders 38312f8add Script: use windeployqt-qt6 in BundleDependencies.sh 2022-12-12 21:58:27 +01:00
Rosalie Wanders d52b1e1b5a RMG: don't link to sdl 2022-12-12 21:58:27 +01:00
Rosalie Wanders 06c9d9b826 3rdParty: update parallel-rdp-standalone 2022-12-12 21:58:27 +01:00
Rosalie Wanders 20a669dbbb 3rdParty: update angrylion-rdp-plus 2022-12-12 21:58:27 +01:00
Rosalie Wanders 68c8c431a2 3rdParty: update GLideN64 2022-12-12 21:58:27 +01:00
Rosalie Wanders d6b1fdfa7b ci: use Qt6 packages 2022-12-12 21:58:27 +01:00
Rosalie Wanders 6ac9208c7f RMG-Input: use Qt6 2022-12-12 21:58:27 +01:00
Rosalie Wanders fdcfaf3fad RMG-Audio: use Qt6 2022-12-12 21:58:27 +01:00
Rosalie Wanders dd08dfafc8 RMG: use Qt6 2022-12-12 21:58:27 +01:00
Rosalie Wanders 22a019abb1 RMG: remove unused included header 2022-12-12 21:58:27 +01:00
Rosalie Wanders e112ae75eb RMG-Input: prepare for Qt6 2022-12-11 22:35:18 +01:00
Rosalie Wanders 0de1073094 RMG: prepare for Qt6 2022-12-11 22:35:06 +01:00
Rosalie Wanders 18a1a6afe6 RMG-Input: fix 'full match' not being correct in ControllerWidget 2022-12-10 22:17:16 +01:00
Rosalie Wanders 149bd86a89 Package: v0.2.4 2022-12-08 15:41:11 +01:00
Rosalie Wanders dbe67853dc RMG-Core: disable Audio_Synchronize by default 2022-12-08 15:23:21 +01:00
Rosalie Wanders 4f30be19b1 3rdParty: update GLideN64 2022-12-08 15:08:47 +01:00
Rosalie Wanders 0347033d89 3rdParty: update mupen64plus-core 2022-12-08 15:08:22 +01:00
Rosalie Wanders 5fc36d5743 RMG: fix InstallUpdateDialog not showing 2022-12-08 15:07:45 +01:00
Rosalie Wanders c745ec18bb cheats: add more cheats from Gent 2022-12-08 14:57:49 +01:00
Rosalie Wanders 0e84317fbc RMG-Core: use dynamic size in CachedRomHeaderAndSettings.cpp 2022-12-08 13:43:03 +01:00
Rosalie Wanders b7df075dec RMG-Core: introduce & use ConvertStringEncoding 2022-12-08 13:42:53 +01:00
Rosalie Wanders da3e30f735 RMG: don't re-initialize Discord Rpc in settings dialog
after CoreDiscordRpcShutdown(), CoreDiscordRpcInit() seems to do nothing.
2022-12-05 22:17:57 +01:00
Rosalie Wanders 9bd0ea0ba6 RMG-Core: properly depend on discord-rpc 2022-12-05 18:43:54 +01:00
Rosalie Wanders 91df63c660 Package: v0.2.3 2022-12-05 17:21:54 +01:00
Rosalie Wanders bea8abd60d 3rdParty: update mupen64plus-core & GLideN64 2022-12-05 17:20:49 +01:00
Rosalie Wanders 86bb226db4 3rdParty: correct discord-rpc BUILD_BYPRODUCTS 2022-12-05 16:40:00 +01:00
Rosalie Wanders 5bbdc7f821 RMG: add check for updates & discord rpc to settings dialog 2022-12-05 16:21:18 +01:00
Rosalie Wanders f23b0ca493 RMG-Core: implement & use DiscordRpc functions 2022-12-05 16:20:35 +01:00
Rosalie Wanders 538b503bcb 3rdParty: add discord-rpc 2022-12-05 16:19:13 +01:00
Rosalie Wanders cabc56550b RMG: introduce an updater 2022-12-04 20:43:33 +01:00
205 changed files with 12591 additions and 3192 deletions
+10 -5
View File
@@ -9,11 +9,14 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: hendrikmuhs/ccache-action@v1.2.5
with:
key: Linux
- name: Install Packages
run: |
sudo apt-get -qq update
sudo apt-get upgrade
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qtbase5-dev libqt5svg5-dev build-essential nasm git zip
sudo apt-get -y install cmake ninja-build libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip
- name: Prepare Environment
run: |
echo "GIT_REVISION=$(git describe --tags --always)" >> $GITHUB_ENV
@@ -32,6 +35,9 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: hendrikmuhs/ccache-action@v1.2.5
with:
key: Windows
- uses: msys2/setup-msys2@v2
with:
path-type: inherit
@@ -39,20 +45,19 @@ jobs:
install: >-
make
mingw-w64-x86_64-cmake
mingw-w64-x86_64-ninja
mingw-w64-x86_64-gcc
mingw-w64-x86_64-hidapi
mingw-w64-x86_64-freetype
mingw-w64-x86_64-libpng
mingw-w64-x86_64-SDL2
mingw-w64-x86_64-jasper
mingw-w64-x86_64-qt5
mingw-w64-x86_64-qt6
mingw-w64-x86_64-SDL2
mingw-w64-x86_64-hidapi
mingw-w64-x86_64-speexdsp
mingw-w64-x86_64-libsamplerate
mingw-w64-x86_64-python3-pip
mingw-w64-x86_64-python3-pyopenssl
mingw-w64-x86_64-nasm
mingw-w64-x86_64-minizip
git
- name: Prepare Environment
run: |
+8 -3
View File
@@ -1,7 +1,12 @@
# CMake build directory
Build/
Bin/
# VSCode Configuration
.vscode/
# Clangd cache
.cache/
.cache/
# Archlinux Package
Package/ArchLinux/pkg/
Package/ArchLinux/rmg/
Package/ArchLinux/src/
Package/ArchLinux/*.pkg.*
# Clangd compile_commands.json
compile_commands.json
+25 -4
View File
@@ -5,6 +5,9 @@ cmake_minimum_required(VERSION 3.15)
option(PORTABLE_INSTALL "Portable Installation" ON)
option(NO_GIT_CLONE "Disables git clone usage for 3rdParty dependencies" OFF)
option(UPDATER "Enables updater" ${PORTABLE_INSTALL})
option(DISCORD_RPC "Enables Discord Rich Presence" ON)
option(USE_CCACHE "Enables usage of ccache when ccache has been found" ON)
project(RMG)
@@ -17,11 +20,25 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (USE_CCACHE)
find_program(CCACHE_FOUND ccache)
if (CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
else(CCACHE_FOUND)
set(USE_CCACHE OFF)
endif(CCACHE_FOUND)
endif(USE_CCACHE)
if (NOT PORTABLE_INSTALL AND (WIN32 OR MSYS))
message(WARNING "Not-Portable build not supported on windows, re-enabling PORTABLE_INSTALL!")
set(PORTABLE_INSTALL ON)
endif()
if (NOT PORTABLE_INSTALL AND UPDATER)
message(WARNING "Not-Portable builds don't support the updater, disabling UPDATER")
set(UPDATER OFF)
endif()
if (PORTABLE_INSTALL)
set(CMAKE_INSTALL_PREFIX "")
set(INSTALL_PATH "Bin/${CMAKE_BUILD_TYPE}")
@@ -41,6 +58,8 @@ else()
set(ICON_INSTALL_PATH "share/icons/hicolor/scalable/apps/")
endif()
add_subdirectory(Source/3rdParty)
add_subdirectory(Source/RMG-Core)
add_subdirectory(Source/RMG)
add_subdirectory(Source/RMG-Audio)
@@ -59,15 +78,17 @@ if (WIN32)
add_subdirectory(Source/Installer)
add_custom_target(bundle_dependencies
COMMAND "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/" "/mingw64/bin"
COMMAND bash "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}" "/mingw64/bin"
)
endif()
endif(WIN32)
add_subdirectory(Source/3rdParty)
install(FILES ${MUPEN64PLUSCORE_LIB}
DESTINATION ${CORE_INSTALL_PATH}
)
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf Data/stylesheet.qss
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf
DESTINATION ${DATA_INSTALL_PATH}
)
install(FILES ${SDL_GAMECONTROLLERDB}
DESTINATION ${DATA_INSTALL_PATH}
)
file(GLOB GENERATED_CHEAT_FILES ${CMAKE_SOURCE_DIR}/Data/Cheats/Generated/*.cht)
@@ -0,0 +1,56 @@
[0CA6AEDA-BB9CFDD9-C:45]
Name=Carnivale - Cenzo's Adventure (USA) (Prototype)
$Infinite Max Silver & Gold Coins
Note=This seems to act as Health?
810A2E7E 001E
810A2E80 001E
810A2E82 001E
$Infinite Max Peas
Note=Max Pea Shooter Ammo
810A2E7A 001E
$Unlock Everything
Note=This Unlocks All Items in Single & All Multi Player Characters and Tracks.(Thanks Retroben!)
810A2E90 0003
810A2E92 87F9
810A2E94 87F9
$Press L for Warp Select (Single Mode)
Note=Press the L-Button as you go through a door (Thanks SubDrag!)
D00A3359 0020
800CA85B 00??
01 Blue Background Race
02 Dark Mountains Race
03 Purple/Yellow Mountains Race
04 Cloud Floor Race (from the locked main area)
05 Main Area
06 Maze
07 King Race Super Rat Ride
08 Mallet Game
09 Duck Game
0A Puppet Show (Come back later)
0B Rock Paper Scissors Game
0C Create Password
0D Main Menu
0E Select New Game
0F Boss Intro Guy with hammer
10 Options Menu
11 Boss Intro Meet Strongman
12 Main Menu
$Max Strength in Mallet Game
811B08A6 0162
$Perfect Aim In Mallet Game (Line up and Shoot)
Note=Use with Max Strength in Mallet Game. Wait until the Eyeball is past the 2 Red Lines (centre) and then press A
811B0BD4 FFF2
811B0B28 FDD2
811605C8 FDD2
81153148 FDD2
$1 Lap to Race (All Characters & Races)
Note=For Single and Multi Player Modes. This will display 1 of 3, but on the first checkpoint you will get the message "You win" 1 Lap to race will also make you come in 1st and win. a big thanks to Parasyte for working with me on this! You are "Magic" lol
81060020 2400
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
[7BD65F9E-76B6A083-C:45]
Name=007 - The World is Not Enough (U) (Prototype - 2020 release)
$Enable Cheats Menu
800811F0 0005
$Invincible
80130ACD 00??
01 On
00 Off
$All Weapons
80130AE0 00??
01 On
00 Off
$All Gadgets
80130AE1 00??
01 On
00 Off
$All Missions
80130AE2 00??
01 On
00 Off
$Infinite Health (All Levels)
81045D68 2400
$Infinite Ammo (All Guns for all Levels)
Note=The Clip will count down but you will never run out of Ammo.
81040730 2400
@@ -0,0 +1,36 @@
[8825E18B-3297746B-C:50]
Name=Aidyn Chronicles - The First Mage (Europe) (Prototype) (2)
$Infinite\Max Health
80279308 001E
$Infinite\99 Health Potions
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
80278D3B 0063
$Have\Max Gold
50000401 0000
80277AA5 00FF
$Have\Max Total XP
50000401 0000
8027931D 00FF
$Have\Max Total XP Remaning to Start
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
50000401 0000
80279321 00FF
$Play As Character
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
810E108E ????
25F9 Alaron
2A43 Marari Female
2C17 Spirit
2CC0 Marari Male
2D4A GiantBat
2E82 Chaos Trooper
3094 Gryphon
324D Ogre
32CC GiantRat
@@ -0,0 +1,36 @@
[8EAA1A2C-61C09930-C:00]
Name=Aidyn Chronicles - The First Mage (USA) (Prototype)
$Infinite\Max Health
80275AA1 001E
$Infinite\99 Health Potions
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
8027540F 0063
$Have\Max Gold
50000401 0000
8027423E 00FF
$Have\Max Total XP
50000401 0000
80275AB6 00FF
$Have\Max Total XP Remaning to Start
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
50000401 0000
80275ABA 00FF
$Play As Character
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
810E0D6E ????
25F9 Alaron
2A43 Marari Female
2C17 Spirit
2CC0 Marari Male
2D4A GiantBat
2E82 Chaos Trooper
3094 Gryphon
324D Ogre
32CC GiantRat
@@ -0,0 +1,29 @@
[A92E0966-341C3912-C:45]
Name=007 - The World is Not Enough (U) (Beta) [!]
$Invincible
8011E157 00??
01 On
00 Off
$Have All Gadgets
8011E159 00??
01 On
00 Off
$Enable All Missions
8011E15A 00??
01 On
00 Off
$Have All Weapons
8011E158 00??
01 On
00 Off
$Infinite Health (All Levels)
8106AC88 2400
$Infinite Ammo (All Guns for all Levels)
8106246C 2400
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,36 @@
[D0E29F11-E029063F-C:50]
Name=Aidyn Chronicles - The First Mage (Europe) (Prototype) (1)
$Infinite\Max Health
80279208 001E
$Infinite\99 Health Potions
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
80278C3B 0063
$Have\Max Gold
50000401 0000
802779A5 00FF
$Have\Max Total XP
50000401 0000
8027921D 00FF
$Have\Max Total XP Remaning to Start
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
50000401 0000
80279221 00FF
$Play As Character
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
810E0F9E ????
25F9 Alaron
2A43 Marari Female
2C17 Spirit
2CC0 Marari Male
2D4A GiantBat
2E82 Chaos Trooper
3094 Gryphon
324D Ogre
32CC GiantRat
@@ -0,0 +1,74 @@
[E48E01F5-E6E51F9B-C:59]
Name=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ita) [!]
$Have Everything Unlocked
Note=This will unlock Cars, Races, Missions and the in-built Cheat Menu. This will also replace all the Zombies with Dinosaurs. To access Cheat menu options: Pause Game: Use Control Stick, to scroll the Cheat Menu. Press A, to activate Cheats
801BE43D 000F
$Have Infinite\Invunerability
81097EAC ????
0BBB On
0000 Off
$Have Infinite\Free Repairs
81097EC4 ????
0BBB On
0000 Off
$Have Infinite\Underwater Ability
81097EF4 ????
0BBB On
0000 Off
$Have Infinite\Turbo
81097E34 ????
0BBB On
0000 Off
$Have Infinite\Mega Turbo
81097E4C ????
0BBB On
0000 Off
$Have Infinite\Hot Rod
81097E64 ????
0BBB On
0000 Off
$Have Infinite\Turbo Nitrous
81097E7C ????
0BBB On
0000 Off
$Have Infinite\Frozen Opponents
81097F24 ????
0BBB On
0000 Off
$Have Infinite\Grip-O-Matic Tires
8109805C ????
0BBB On
0000 Off
$Have Infinite\Mine Dropping Ability
81098118 ????
0064 On
0000 Off
$Freeze Timer at 04:59
Note=Do not enable until count down to race is finished
811BE21E 3A70
$Max Credits
Note=This is also Infinite until disabled
811BE29A FFFF
$Max Kills
Note=This will automatically Clear the stage if enabled and go back to the stage menu
81094BEE 01F4
$Have All Groups Completed
Note=This gives you all Cups for all Groups.
50002801 0000
801BE35C 0002
@@ -0,0 +1,74 @@
[F1642508-BEE60CF6-C:45]
Name=Bust-A-Move 3 DX (USA) (Prototype)
$Always Have\guide line on
800558CC 0082
$Pointer always active
D0055BA0 0002
80055BA0 0082
$Play As Select\Player 1
800E1E50 00??
00 Bubbloon
01 Twinkie
02 Prettio
03 Marina
04 Musashi
05 Luna
06 Jack
07 SSB
08 Dragoon
09 Gnome
10 Monkey
11 furby? (looks like 2 balloons)
12 Blue Gnome
13 1 of the two Ballons
14 Water under ballons
$Play As Select\Player 2
800E1E58 00??
00 Bubbloon
01 Twinkie
02 Prettio
03 Marina
04 Musashi
05 Luna
06 Jack
07 SSB
08 Dragoon
09 Gnome
10 Monkey
11 furby? (looks like 2 balloons)
12 Blue Gnome
13 1 of the two Ballons
14 Water under ballons
$Next Bubble Select\Player 1
800EBA19 00??
00 No Bubble
01 Red
02 Green
03 Blue
04 Yellow
05 Orange
06 Purple
07 White
08 Black
$Next Bubble Select\Player 2
800EBB09 00??
00 No Bubble
01 Red
02 Green
03 Blue
04 Yellow
05 Orange
06 Purple
07 White
08 Black
$Press GS Button to Reset Player 2 score to 0
8809C5C0 0000
8809C5C2 0000
@@ -0,0 +1,25 @@
[F7AA4F819F41CB4236792A8145684627]
Name=Yoshi's Story (CHN) (iQue)
$Infinite\Health
Note=This is for All Yoshis All levels
50000804 0000
8012FD1F 00??
08 Infinite Health
09 Infinite Max Health
$Infinite\Eggs (Once You Get One)
Note=This is for All Yoshis All levels
8103E52C 2400
$Infinite\Lives
Note=This is for All Yoshis All levels
8012FD5F 00FF
$Press GS Button To Have All Fruit
8812F93B 001E
$Enable All Levels (Trial Mode)
8112FDC4 FFFF
8112FDC6 FFFF
+7 -12
View File
@@ -11,8 +11,8 @@ license=('GPLv3')
provides=("$_pkgname")
conflicts=("$_pkgname")
depends=("hidapi" "libsamplerate" "minizip" "sdl2" "zlib" "freetype2" "qt5-base" "qt5-svg")
makedepends=("git" "pkg-config" "nasm" "cmake" "rustup")
depends=("hidapi" "libsamplerate" "minizip" "sdl2" "zlib" "freetype2" "qt6-base" "qt6-svg" "xdg-user-dirs")
makedepends=("git" "pkg-config" "nasm" "cmake" "cargo" "ninja")
source=("git+https://github.com/Rosalie241/${_pkgname}.git")
sha256sums=('SKIP')
@@ -26,26 +26,21 @@ pkgver()
prepare()
{
cd "$srcdir/${_pkgname}"
mkdir -p build
mkdir -p "$srcdir/${_pkgname}/build"
}
build()
{
cd "$srcdir/${_pkgname}/build"
cmake -S "$srcdir/${_pkgname}" -B "$srcdir/${_pkgname}/build" \
-DCMAKE_BUILD_TYPE="Release" \
-DPORTABLE_INSTALL="OFF" \
-DCMAKE_INSTALL_PREFIX="/usr" \
-G "Unix Makefiles"
make
-G "Ninja" \
cmake --build "$srcdir/${_pkgname}/build"
}
package()
{
cd "$srcdir/${_pkgname}/build"
make install DESTDIR="$pkgdir"
cmake --install "$srcdir/${_pkgname}/build" --prefix="$pkgdir/usr"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 47 KiB

@@ -18,13 +18,184 @@
<caption>During A Game</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InGame.png</image>
</screenshot>
<screenshot type="default">
<caption>Cheats</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Cheats.png</image>
</screenshot>
<screenshot type="default">
<caption>Settings</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Settings.png</image>
</screenshot>
<screenshot type="default">
<caption>Input Settings</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InputSettings.png</image>
</screenshot>
</screenshots>
<description/>
<releases>
<release version="v0.3.2" date="2023-02-06" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix ndd/d64 files in zip files not working when the disk file is inside a subdirectory inside the zip file</li>
<li>Fix ndd/d64 files in zip files not working correctly on windows</li>
<li>Fix controller image in RMG-Input sometimes being stuck when having a trigger bound to a button</li>
<li>Fix trigger mapping in RMG-Input</li>
<li>Remove "Invert Axis Mapped To LRZ" setting in RMG-Input</li>
<li>Add "Sort Results After Search" ROM Browser setting</li>
</ul>
</description>
</release>
<release version="v0.3.1" date="2023-02-04" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix taking a screenshot not working in some cases</li>
<li>Fix some games being unable to save due to having an illegal character in the save filename</li>
<li>Fix OSD tab crash in GLideN64</li>
<li>Fix an issue where the graphics plugin would show the 64DD IPL as ROM name in the settings even after booting a cartridge</li>
<li>Fix "Refresh ROM List" in Hotkeys tab in settings dialog not reverting back to defaults when clicking on 'restore defaults'</li>
<li>Fix "Remove Duplicate Keybindings" in settings dialog not behaving correctly in some cases</li>
<li>Fix fallback application icons not respecting system icon theme on linux</li>
<li>Add support for ndd/d64 files in zip files</li>
<li>Add support for using the basename of the ROM filename for covers</li>
<li>Add support for binding multiple inputs in RMG-Input</li>
<li>Improve behavior of window when launching RMG with a ROM using the commandline</li>
<li>Improve behavior of error message when emulation fails</li>
<li>Improve behavior of hotkey buttons in settings dialog</li>
</ul>
</description>
</release>
<release version="v0.3.0" date="2023-01-23" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix GLideN64 not being able to load texture packs from relative paths</li>
<li>Fix "Save State Slot" keybindings not working in fullscreen</li>
<li>Fix deadzone percentage being incorrect when set to 0% in RMG-Input</li>
<li>Fix low deadzone value not working in RMG-Input (thank you porcino)</li>
<li>Fix toolbar being hidden when ending emulation while in fullscreen</li>
<li>Fix zip files with japanese characters in the file name not being able to be opened on windows</li>
<li>Fix ROM Browser not returning to a maximized state when ending emulation</li>
<li>Fix ROM Browser not opening maximized when closing RMG with it maximized</li>
<li>Fix window not being able to be maximized during emulation when scaling is enabled</li>
<li>Fix read-only ROM files not being able to be opened on linux</li>
<li>Remove "Allow Manual Window Resizing" setting due to it being always enabled</li>
<li>Remove Styles tab from settings dialog on windows</li>
<li>Add "Play Game with Cartridge" to context menu when a 64DD disk is selected in the ROM Browser</li>
<li>Add "Open ROM Directory" to context menu in the ROM Browser</li>
<li>Add an On-Screen Display (see the OSD tab in the settings dialog for settings)</li>
<li>Add Theme setting to settings dialog (see Interface -> Miscellaneous, this is a replacement for the previous Styles settings)</li>
<li>Improve error message when opening a zip file fails</li>
<li>Improve tab order and naming in settings dialog</li>
</ul>
</description>
</release>
<release version="v0.2.9" date="2023-01-03" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix wrong 64DD Disk extension being listed in empty ROM browser</li>
<li>Fix memory corruption when having 64DD Disk files</li>
<li>Fix possible crash when render window wasn't visible yet</li>
<li>Fix RMG changing the current directory on non-portable installs</li>
<li>Remove Qt warning messages (you can view them by setting RMG_SHOW_DEBUG_QT_MESSAGES to 1)</li>
<li>Change "Choose ROM Directory" to "Change ROM Directory"</li>
<li>Add -q/--quit-after-emulation commandline option</li>
<li>Add 2 more icons to menubar menus/items</li>
<li>Add "Current Save State" tab to Hotkeys tab in settings dialog (this allows you to use a hotkey to change save state slots)</li>
<li>Improve behavior of Hotkeys tab in settings dialog</li>
<li>Improve behavior of window when exiting RMG while in-game</li>
</ul>
</description>
</release>
<release version="v0.2.8" date="2023-01-01" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix 'Uniform Size (Grid View)' not being disabled during emulation</li>
<li>Fix toolbar not respecting the view setting</li>
<li>Fix being stuck at the loading screen when having more ROMs than the ROM search limit</li>
<li>Improve error message when opening a ROM fails</li>
</ul>
</description>
</release>
<release version="v0.2.7" date="2022-12-29" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix core error not showing when the statusbar was hidden</li>
<li>Fix .ndd/.64d not being in the empty ROM Browser widget</li>
<li>Fix .jpg/.jpeg files not working on covers on Windows</li>
<li>Fix updater script not copying subdirectories on Windows (for portable installs)</li>
<li>Fix 64DD Disks which required the development IPL not working</li>
<li>Fix 64DD Disks showing the wrong internal ROM name (this fix requires clearing the ROM cache)</li>
<li>Fix cover filenames allowing invalid characters (they will now be replaced by _)</li>
<li>Add more icons to View menu in the menu bar</li>
<li>Add 'Uniform Size (Grid View)' to View menu in the menu bar</li>
<li>Add smooth scrolling to List View and Grid View</li>
</ul>
</description>
</release>
<release version="v0.2.6" date="2022-12-28" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix default save state/game directory being incorrect on first run (on non-portable installs)</li>
<li>Fix angrylion-rdp-plus not loading settings correctly</li>
<li>Fix cheat settings not moving over when renaming a cheat</li>
<li>Remove fullscreen resolution combobox from GLideN64 because it did nothing</li>
<li>Remove File menu from menu bar</li>
<li>Implement disk support without requiring a cartridge</li>
<li>Add toolbar</li>
<li>Add View menu to menu bar</li>
<li>Add Grid view to ROM browser</li>
<li>Add icons to all menu bar items</li>
<li>Add log dialog</li>
</ul>
</description>
</release>
<release version="v0.2.5" date="2022-12-14" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix incorrect controller being selected in RMG-Input when having 2 controllers with the same name</li>
<li>Fix some UI elements being enabled while the 'Controller Is Plugged In' checkbox is disabled in RMG-Input</li>
<li>Fix extra padding being added when having a controller selected and opening RMG-Input</li>
<li>Fix creating a new profile in GLideN64</li>
<li>Add Z-Trigger visualization in RMG-Input</li>
<li>Remove Debugger checkbox in the settings dialog because it did nothing</li>
<li>Remove About buttons in the plugin tab of the settings dialog because it did nothing</li>
<li>Implement close button on all dialogs</li>
<li>Implement custom style support (for Windows only)</li>
<li>Implement the ability to remove/reset the main profile in RMG-Input</li>
<li>Rename Interface tab in settings dialog to User Interface</li>
<li>Migrate to Qt6 (currently the flatpak will remain Qt5)</li>
</ul>
</description>
</release>
<release version="v0.2.4" date="2022-12-08" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix Discord Rich Presence breaking when opening the settings dialog</li>
<li>Fix install update window not showing</li>
<li>Fix 'Limit FPS' not working with new RMG-Audio (this disables the 'synchronize audio' option)</li>
<li>Implement support for Japanese characters in the ROM header</li>
<li>Implement dynamic buffer sizes in the ROM browser cache (this reduces the ROM browser cache size)</li>
<li>Add more cheats from Gent</li>
</ul>
</description>
</release>
<release version="v0.2.3" date="2022-12-05" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Add updater for portable installations</li>
<li>Add Discord Rich Presence</li>
</ul>
</description>
</release>
<release version="v0.2.2" date="2022-12-03" type="stable">
<description>
<p>Changes:</p>
+43 -45
View File
@@ -4,51 +4,6 @@ Rosalie's Mupen GUI is a free and open-source mupen64plus GUI written in C++.
It offers a simple-to-use user interface.
## System Requirements
* Operating System
* Windows Or Linux
* CPU
* Intel or AMD processor with SSE2 support
* RAM
* 512MB or more
* Graphics card
* OpenGL 3.3 capable
## Building
#### Linux
* Portable Debian/Ubuntu
```shell
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt5-default build-essential nasm git zip
./Source/Script/Build.sh Release
```
* Portable Fedora
```shell
sudo dnf install hidapi-devel libsamplerate-devel minizip-compat-devel SDL2-devel freetype-devel mesa-libGL-devel mesa-libGLU-devel zlib-ng-devel binutils-devel speexdsp-devel qt5-qtbase-devel qt5-qtsvg-devel gcc-c++ nasm git
./Source/Script/Build.sh Release
```
When it's done building, executables can be found in `Bin/Release`
* Installation/Packaging
```
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -G "Unix Makefiles"
make install
```
#### Windows
* Download & Install [MSYS2](https://www.msys2.org/)
```
sudo pacman -S git make mingw-w64-x86_64-cmake mingw-w64-x86_64-freetype mingw-w64-x86_64-gcc mingw-w64-x86_64-hidapi mingw-w64-x86_64-jasper mingw-w64-x86_64-libpng mingw-w64-x86_64-libsamplerate mingw-w64-x86_64-nasm mingw-w64-x86_64-python3-pip mingw-w64-x86_64-python3-pyopenssl mingw-w64-x86_64-qt5 mingw-w64-x86_64-rust mingw-w64-x86_64-SDL2
./Source/Script/Build.sh Release
```
When it's done building, executables can be found in `Bin/Release`
## Support
Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for support
@@ -56,3 +11,46 @@ Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for
## License
Rosalie's Mupen GUI is licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
## Showcase
![RomBrowser](Package/Screenshots/RomBrowser.png)
![InGame](Package/Screenshots/InGame.png)
![InputSettings](Package/Screenshots/InputSettings.png)
## Building
#### Linux
* Portable Debian/Ubuntu
```bash
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip ninja-build
./Source/Script/Build.sh Release
```
* Portable Fedora
```bash
sudo dnf install hidapi-devel libsamplerate-devel minizip-compat-devel SDL2-devel freetype-devel mesa-libGL-devel mesa-libGLU-devel zlib-ng-devel binutils-devel speexdsp-devel qt6-qtbase-devel qt6-qtsvg-devel gcc-c++ nasm git ninja-build
./Source/Script/Build.sh Release
```
When it's done building, executables can be found in `Bin/Release`
* Installation/Packaging
```bash
export src_dir="$(pwd)"
export build_dir="$(pwd)/build"
mkdir -p "$build_dir"
cmake -S "$src_dir" -B "$build_dir" -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -DCMAKE_INSTALL_PREFIX="/usr" -G "Ninja"
cmake --build "$build_dir"
cmake --install "$build_dir" --prefix="/usr"
```
#### Windows
* Download & Install [MSYS2](https://www.msys2.org/)
```bash
pacman -S --needed make mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-hidapi mingw-w64-x86_64-freetype mingw-w64-x86_64-libpng mingw-w64-x86_64-SDL2 mingw-w64-x86_64-qt6 mingw-w64-x86_64-SDL2 mingw-w64-x86_64-hidapi mingw-w64-x86_64-speexdsp mingw-w64-x86_64-libsamplerate mingw-w64-x86_64-nasm mingw-w64-x86_64-minizip git
./Source/Script/Build.sh Release
```
When it's done building, executables can be found in `Bin/Release`
+126 -25
View File
@@ -8,9 +8,9 @@ set(THIRDPARTY_DIR ${CMAKE_BINARY_DIR}/Source/3rdParty)
find_program(RUST_CARGO cargo)
if(${RUST_CARGO} STREQUAL "RUST_CARGO-NOTFOUND")
message(WARNING "mupen64plus-input-gca will not be built due to not having cargo installed")
set(BUILD_INPUT_GCA "0")
set(BUILD_INPUT_GCA OFF)
else()
set(BUILD_INPUT_GCA "1")
set(BUILD_INPUT_GCA ON)
endif()
set(M64P_CORE_DIR ${THIRDPARTY_DIR}/mupen64plus-core)
@@ -24,9 +24,20 @@ else(WIN32)
set(CORE_FILE "libmupen64plus.so")
endif(WIN32)
set(BASE_CMAKE_CONFIGURE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
if (USE_CCACHE)
set(CMAKE_CONFIGURE_ARGS ${BASE_CMAKE_CONFIGURE_ARGS} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache)
set(MAKE_CC_COMPILER "ccache ${CMAKE_C_COMPILER}")
set(MAKE_CXX_COMPILER "ccache ${CMAKE_CXX_COMPILER}")
else(USE_CCACHE)
set(CMAKE_CONFIGURE_ARGS ${BASE_CMAKE_CONFIGURE_ARGS})
set(MAKE_CC_COMPILER "${CMAKE_C_COMPILER}")
set(MAKE_CXX_COMPILER "${CMAKE_CXX_COMPILER}")
endif(USE_CCACHE)
if(NOT NO_GIT_CLONE)
set(MUPEN64PLUSCORE_URL "https://github.com/mupen64plus/mupen64plus-core")
set(MUPEN64PLUSCORE_TAG "f63e1b35063241738d848f73311496b76c8aa918")
set(MUPEN64PLUSCORE_URL "https://github.com/Rosalie241/mupen64plus-core")
set(MUPEN64PLUSCORE_TAG "022e7de28067ac633ca23d405e9f0c4ed5cc368b")
set(MUPEN64PLUS_RSP_CXD4_URL "https://github.com/mupen64plus/mupen64plus-rsp-cxd4")
set(MUPEN64PLUS_RSP_CXD4_TAG "39f79201baa15890c4cbae92f2215a634cc3ee6d")
@@ -44,13 +55,22 @@ if(NOT NO_GIT_CLONE)
set(MUPEN64PLUS_INPUT_GCA_TAG "21639fb13dfa797a7c0949ffd9bbda9a3456fc69")
set(MUPEN64PLUS_GFX_ANGRYLION_URL "https://github.com/Rosalie241/angrylion-rdp-plus")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "9d71074f6b71750e99ad06a713f28a9c32ad15cb")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "158e74d4ec1c818289cd19c3a05e498c3ceff758")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/gonetz/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "a2ecb92e954fdc1dd1130b331935f04381b29e28")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "263a7bd2ca81759ece98209bd282a6c1173a129f")
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "693f607728aca78d94ba5d45b0ce119b4ccbcd8c")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "48abaa5e082add7848e6f98648111c69c4a71632")
set(DISCORD_RPC_URL "https://github.com/discord/discord-rpc")
set(DISCORD_RPC_TAG "963aa9f3e5ce81a4682c6ca3d136cddda614db33")
set(IMGUI_URL "https://github.com/ocornut/imgui")
set(IMGUI_TAG "d7c8516a4b848c0291e3d75b627c0843f515f591")
set(SDL_GAMECONTROLLERDB_URL "https://github.com/gabomdq/SDL_GameControllerDB")
set(SDL_GAMECONTROLLERDB_TAG "0562b00eaf5c0308c49d329b79263d2dae1c3a85")
endif(NOT NO_GIT_CLONE)
ExternalProject_Add(mupen64plus-core
@@ -62,7 +82,7 @@ ExternalProject_Add(mupen64plus-core
GIT_REPOSITORY ${MUPEN64PLUSCORE_URL}
GIT_TAG ${MUPEN64PLUSCORE_TAG}
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0 CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_IN_SOURCE False
BINARY_DIR ${M64P_CORE_DIR}/projects/unix
@@ -81,7 +101,7 @@ ExternalProject_Add(mupen64plus-rsp-cxd4
GIT_REPOSITORY ${MUPEN64PLUS_RSP_CXD4_URL}
GIT_TAG ${MUPEN64PLUS_RSP_CXD4_TAG}
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> POSTFIX=
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> POSTFIX= CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_IN_SOURCE False
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-cxd4/projects/unix
@@ -99,7 +119,7 @@ ExternalProject_Add(mupen64plus-rsp-hle
GIT_REPOSITORY ${MUPEN64PLUS_RSP_HLE_URL}
GIT_TAG ${MUPEN64PLUS_RSP_HLE_TAG}
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug>
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_IN_SOURCE False
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-hle/projects/unix
@@ -117,7 +137,7 @@ ExternalProject_Add(mupen64plus-rsp-parallel
INSTALL_COMMAND ""
BUILD_IN_SOURCE True
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
CMAKE_ARGS ${CMAKE_CONFIGURE_ARGS}
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-rsp-parallel/mupen64plus-rsp-parallel.${SO_EXT}
DEPENDS mupen64plus-core
@@ -132,7 +152,7 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
GIT_REPOSITORY ${MUPEN64PLUS_INPUT_RAPHNET_URL}
GIT_TAG ${MUPEN64PLUS_INPUT_RAPHNET_TAG}
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug>
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_IN_SOURCE False
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-input-raphnetraw/projects/unix
@@ -141,7 +161,7 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
DEPENDS mupen64plus-core
)
if (${BUILD_INPUT_GCA} STREQUAL "1")
if (BUILD_INPUT_GCA)
ExternalProject_Add(mupen64plus-input-gca
SOURCE_DIR mupen64plus-input-gca/
@@ -157,15 +177,16 @@ if (${BUILD_INPUT_GCA} STREQUAL "1")
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-gca/target/release/${GCA_LIB}
DEPENDS mupen64plus-core
)
endif()
endif(BUILD_INPUT_GCA)
set(GLIDEN64_DIR "${THIRDPARTY_DIR}/mupen64plus-video-GLideN64")
set(GLIDEN64_BUILD_DIR "${GLIDEN64_DIR}/projects/cmake")
if (MSYS)
set(GLIDEN64_CUSTOM_INI "${GLIDEN64_DIR}/ini/GLideN64.custom.ini")
if (WIN32)
set(GLIDEN64_LIB "${GLIDEN64_BUILD_DIR}/mupen64plus-video-GLideN64.${SO_EXT}")
else()
else(WIN32)
set(GLIDEN64_LIB "${GLIDEN64_BUILD_DIR}/plugin/${CMAKE_BUILD_TYPE}/mupen64plus-video-GLideN64.${SO_EXT}")
endif()
endif(WIN32)
set(GLIDENUI_TRANSLATIONS_LANGS "de;es;fr;it;ja;pl;pt_BR")
foreach(LANG ${GLIDENUI_TRANSLATIONS_LANGS})
@@ -181,7 +202,7 @@ ExternalProject_Add(mupen64plus-video-angrylion-plus
INSTALL_COMMAND ""
BUILD_IN_SOURCE True
CMAKE_ARGS -DBUILD_MUPEN64PLUS=ON -DBUILD_PROJECT64=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
CMAKE_ARGS -DBUILD_MUPEN64PLUS=ON -DBUILD_PROJECT64=OFF -DUSE_QT5=OFF ${CMAKE_CONFIGURE_ARGS}
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-video-angrylion-plus/mupen64plus-video-angrylion-plus.${SO_EXT}
DEPENDS mupen64plus-core
@@ -196,14 +217,12 @@ ExternalProject_Add(mupen64plus-video-GLideN64
INSTALL_COMMAND ""
BUILD_IN_SOURCE False
CMAKE_ARGS -DMUPENPLUSAPI=ON -DMUPENPLUSAPI_GLIDENUI=ON -DUSE_SYSTEM_LIBS=ON -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
CMAKE_ARGS -DMUPENPLUSAPI=ON -DMUPENPLUSAPI_GLIDENUI=ON -DGLIDENUI_QT6=ON -DUSE_SYSTEM_LIBS=ON ${CMAKE_CONFIGURE_ARGS}
SOURCE_SUBDIR ./src/
BINARY_DIR ${GLIDEN64_BUILD_DIR}
BUILD_BYPRODUCTS ${GLIDEN64_LIB}
BUILD_BYPRODUCTS ${GLIDEN64_DIR}/ini/GLideN64.custom.ini
BUILD_BYPRODUCTS ${GLIDENUI_TRANSLATIONS}
)
ExternalProject_Add(mupen64plus-video-parallel
@@ -215,12 +234,82 @@ ExternalProject_Add(mupen64plus-video-parallel
INSTALL_COMMAND ""
BUILD_IN_SOURCE True
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
CMAKE_ARGS -DUSE_QT5=OFF ${CMAKE_CONFIGURE_ARGS}
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-video-parallel/mupen64plus-video-parallel.${SO_EXT}
DEPENDS mupen64plus-core
)
if (DISCORD_RPC)
ExternalProject_Add(discord-rpc
SOURCE_DIR discord-rpc
GIT_REPOSITORY ${DISCORD_RPC_URL}
GIT_TAG ${DISCORD_RPC_TAG}
INSTALL_COMMAND ""
BUILD_IN_SOURCE True
CMAKE_ARGS -DBUILD_EXAMPLES=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON ${CMAKE_CONFIGURE_ARGS}
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/discord-rpc/src/libdiscord-rpc.a
)
endif(DISCORD_RPC)
set(IMGUI_DIR ${THIRDPARTY_DIR}/imgui)
set(IMGUI_BUILD_DIR ${IMGUI_DIR}/build)
set(IMGUI_SOURCES_IN
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_widgets.cpp
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp
${IMGUI_DIR}/backends/imgui_impl_opengl3.h
${IMGUI_DIR}/backends/imgui_impl_opengl3_loader.h
)
set(IMGUI_SOURCES_OUT
${IMGUI_BUILD_DIR}/imgui_draw.cpp
${IMGUI_BUILD_DIR}/imgui_tables.cpp
${IMGUI_BUILD_DIR}/imgui_widgets.cpp
${IMGUI_BUILD_DIR}/imgui.cpp
${IMGUI_BUILD_DIR}/imgui_impl_opengl3.cpp
${IMGUI_BUILD_DIR}/imgui_impl_opengl3.h
${IMGUI_BUILD_DIR}/imgui_impl_opengl3_loader.h
)
ExternalProject_Add(imgui
SOURCE_DIR imgui
GIT_REPOSITORY ${IMGUI_URL}
GIT_TAG ${IMGUI_TAG}
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${IMGUI_BUILD_DIR}
BUILD_COMMAND ${CMAKE_COMMAND} -E copy ${IMGUI_SOURCES_IN} ${IMGUI_BUILD_DIR}
INSTALL_COMMAND ""
BUILD_BYPRODUCTS ${IMGUI_SOURCES_OUT}
)
set(SDL_GAMECONTROLLERDB_DIR ${THIRDPARTY_DIR}/SDL_GameControllerDB)
set(SDL_GAMECONTROLLERDB_BUILD_DIR ${SDL_GAMECONTROLLERDB_DIR}/build)
set(SDL_GAMECONTROLLERDB_SOURCES_IN
${SDL_GAMECONTROLLERDB_DIR}/gamecontrollerdb.txt
)
set(SDL_GAMECONTROLLERDB_SOURCES_OUT
${SDL_GAMECONTROLLERDB_BUILD_DIR}/gamecontrollerdb.txt
)
ExternalProject_Add(SDL_GameControllerDB
SOURCE_DIR SDL_GameControllerDB
GIT_REPOSITORY ${SDL_GAMECONTROLLERDB_URL}
GIT_TAG ${SDL_GAMECONTROLLERDB_TAG}
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${SDL_GAMECONTROLLERDB_BUILD_DIR}
BUILD_COMMAND ${CMAKE_COMMAND} -E copy ${SDL_GAMECONTROLLERDB_SOURCES_IN} ${SDL_GAMECONTROLLERDB_SOURCES_OUT}
INSTALL_COMMAND ""
BUILD_BYPRODUCTS ${SDL_GAMECONTROLLERDB_SOURCES_OUT}
)
ExternalProject_Get_property(mupen64plus-core BUILD_BYPRODUCTS)
set(MUPEN64PLUSCORE_LIB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
set(MUPEN64PLUSCORE_INI ${M64P_CORE_DIR}/data/mupen64plus.ini PARENT_SCOPE)
@@ -237,16 +326,28 @@ set(MUPEN64PLUS_PLUGIN_RSP_PARALLEL ${BUILD_BYPRODUCTS} PARENT_SCOPE)
ExternalProject_Get_property(mupen64plus-input-raphnetraw BUILD_BYPRODUCTS)
set(MUPEN64PLUS_PLUGIN_INPUT_RAPHNET ${BUILD_BYPRODUCTS} PARENT_SCOPE)
if (${BUILD_INPUT_GCA} STREQUAL "1")
if (BUILD_INPUT_GCA)
ExternalProject_Get_property(mupen64plus-input-gca BUILD_BYPRODUCTS)
set(MUPEN64PLUS_PLUGIN_INPUT_GCA ${BUILD_BYPRODUCTS} PARENT_SCOPE)
endif()
endif(BUILD_INPUT_GCA)
ExternalProject_Get_property(mupen64plus-video-angrylion-plus BUILD_BYPRODUCTS)
set(MUPEN64PLUS_PLUGIN_GFX_ANGRYLION ${BUILD_BYPRODUCTS} PARENT_SCOPE)
ExternalProject_Get_property(mupen64plus-video-GLideN64 BUILD_BYPRODUCTS)
set(MUPEN64PLUS_PLUGIN_GFX_GLIDEN64 ${BUILD_BYPRODUCTS} PARENT_SCOPE)
set(MUPEN64PLUS_PLUGIN_GFX_GLIDEN64 ${BUILD_BYPRODUCTS} ${GLIDENUI_TRANSLATIONS} ${GLIDEN64_CUSTOM_INI} PARENT_SCOPE)
ExternalProject_Get_property(mupen64plus-video-parallel BUILD_BYPRODUCTS)
set(MUPEN64PLUS_PLUGIN_GFX_PARALLEL ${BUILD_BYPRODUCTS} PARENT_SCOPE)
if (DISCORD_RPC)
ExternalProject_Get_property(discord-rpc BUILD_BYPRODUCTS)
set(DISCORD_RPC_LIB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
endif(DISCORD_RPC)
ExternalProject_Get_property(imgui BUILD_BYPRODUCTS)
set(IMGUI_SOURCES ${BUILD_BYPRODUCTS} PARENT_SCOPE)
set(IMGUI_DIR ${THIRDPARTY_DIR}/imgui PARENT_SCOPE)
ExternalProject_Get_property(SDL_GameControllerDB BUILD_BYPRODUCTS)
set(SDL_GAMECONTROLLERDB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
+2 -2
View File
@@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5 COMPONENTS Gui Widgets Core REQUIRED)
find_package(Qt6 COMPONENTS Gui Widgets Core REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
@@ -36,7 +36,7 @@ target_link_libraries(RMG-Audio
${SDL2_LIBRARIES}
${SPEEX_LIBRARIES}
${SAMPLERATE_LIBRARIES}
Qt5::Gui Qt5::Widgets
Qt6::Gui Qt6::Widgets
)
target_include_directories(RMG-Audio PRIVATE
+18 -1
View File
@@ -12,11 +12,13 @@
using namespace UserInterface;
MainDialog::MainDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
MainDialog::MainDialog(QWidget* parent) : QDialog(parent)
{
this->setupUi(this);
this->setWindowIcon(QIcon(":Resource/RMG.png"));
this->setIconsForEmulationInfoText();
this->volumeSlider->setValue(CoreSettingsGetIntValue(SettingsID::Audio_Volume));
this->muteCheckBox->setChecked(CoreSettingsGetBoolValue(SettingsID::Audio_Muted));
@@ -38,6 +40,21 @@ MainDialog::~MainDialog()
{
}
void MainDialog::setIconsForEmulationInfoText(void)
{
QLabel* labels[] = {
this->infoIconLabel_0
};
QIcon infoIcon = QIcon::fromTheme("information-line");
QPixmap infoIconPixmap = infoIcon.pixmap(16, 16);
for (QLabel* label : labels)
{
label->setPixmap(infoIconPixmap);
}
}
void MainDialog::hideEmulationInfoText(void)
{
QHBoxLayout *layouts[] = {this->emulationInfoLayout};
@@ -25,6 +25,7 @@ public:
~MainDialog(void);
private:
void setIconsForEmulationInfoText(void);
void hideEmulationInfoText(void);
private slots:
+2 -2
View File
@@ -324,7 +324,7 @@
<item>
<layout class="QHBoxLayout" name="emulationInfoLayout">
<item>
<widget class="QLabel" name="label_6">
<widget class="QLabel" name="infoIconLabel_0">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
@@ -335,7 +335,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="UIResources.qrc">:/Resource/Info.ico</pixmap>
<pixmap>:/Resource/Info.ico</pixmap>
</property>
<property name="scaledContents">
<bool>false</bool>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,6 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>Resource/RMG.png</file>
<file>Resource/Info.ico</file>
</qresource>
</RCC>
+22 -2
View File
@@ -9,6 +9,9 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
pkg_check_modules(MINIZIP REQUIRED minizip)
if (WIN32)
pkg_check_modules(ICONV REQUIRED iconv)
endif(WIN32)
configure_file(Config.hpp.in Config.hpp)
@@ -18,6 +21,7 @@ set(RMG_CORE_SOURCES
m64p/ConfigApi.cpp
m64p/PluginApi.cpp
CachedRomHeaderAndSettings.cpp
ConvertStringEncoding.cpp
Settings/Settings.cpp
SpeedLimiter.cpp
RomSettings.cpp
@@ -29,10 +33,12 @@ set(RMG_CORE_SOURCES
SaveState.cpp
Callback.cpp
Plugins.cpp
Version.cpp
Cheats.cpp
VidExt.cpp
Video.cpp
Error.cpp
Unzip.cpp
Core.cpp
Key.cpp
Rom.cpp
@@ -50,8 +56,15 @@ else()
)
endif()
if (DISCORD_RPC)
list(APPEND RMG_CORE_SOURCES
DiscordRpc.cpp
)
add_definitions(-DDISCORD_RPC)
endif(DISCORD_RPC)
if (PORTABLE_INSTALL)
add_definitions(-DPORTABLE_INSTALL)
add_definitions(-DPORTABLE_INSTALL)
endif(PORTABLE_INSTALL)
add_library(RMG-Core STATIC ${RMG_CORE_SOURCES})
@@ -61,13 +74,20 @@ if(UNIX)
endif(UNIX)
if(WIN32)
target_link_libraries(RMG-Core wsock32 ws2_32)
target_link_libraries(RMG-Core wsock32 ws2_32 ${ICONV_LIBRARIES})
endif(WIN32)
target_link_libraries(RMG-Core
${MINIZIP_LIBRARIES}
)
if (DISCORD_RPC)
target_link_libraries(RMG-Core
${DISCORD_RPC_LIB}
)
add_dependencies(RMG-Core discord-rpc)
endif(DISCORD_RPC)
target_include_directories(RMG-Core PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
+59 -15
View File
@@ -18,16 +18,30 @@
#include <fstream>
#include <algorithm>
#ifdef _WIN32
#include <Windows.h>
#else // Linux
#include <linux/limits.h>
#endif // _WIN32
//
// Local Defines
//
#define MAX_FILENAME_LEN 4096
#define ROMHEADER_NAME_LEN 21
#ifdef _WIN32
#define MAX_FILENAME_LEN MAX_PATH
#else // Linux
#define MAX_FILENAME_LEN PATH_MAX
#endif // _WIN32
#define ROMHEADER_NAME_LEN 256
#define GOODNAME_LEN 256
#define MD5_LEN 33
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCache_03"
#ifdef _WIN32
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheWindows_05"
#else // Linux
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheLinux_05"
#endif // _WIN32
#define CACHE_FILE_ITEMS_MAX 10000
//
@@ -39,6 +53,7 @@ struct l_CacheEntry
std::filesystem::path fileName;
osal_files_file_time fileTime;
CoreRomType type;
CoreRomHeader header;
CoreRomSettings settings;
};
@@ -90,6 +105,7 @@ void CoreReadRomHeaderAndSettingsCache(void)
char headerNameBuf[ROMHEADER_NAME_LEN];
char goodNameBuf[GOODNAME_LEN];
char md5Buf[MD5_LEN];
uint32_t size;
l_CacheEntry cacheEntry;
inputStream.open(get_cache_file_name(), std::ios::binary);
@@ -108,27 +124,34 @@ void CoreReadRomHeaderAndSettingsCache(void)
// read all file entries
#define FREAD(x) inputStream.read((char*)&x, sizeof(x))
#define FREAD_STR(x) inputStream.read((char*)x, sizeof(x))
#define FREAD_STR(x, y) inputStream.read((char*)x, y)
while (!inputStream.eof())
{
// reset buffers
size = 0;
memset(fileNameBuf, 0, sizeof(fileNameBuf));
memset(headerNameBuf, 0, sizeof(headerNameBuf));
memset(goodNameBuf, 0, sizeof(goodNameBuf));
memset(md5Buf, 0, sizeof(md5Buf));
// file info
FREAD_STR(fileNameBuf);
FREAD(size);
FREAD_STR(fileNameBuf, size);
cacheEntry.fileName = std::filesystem::path(fileNameBuf);
FREAD(cacheEntry.fileTime);
// type
FREAD(cacheEntry.type);
// header
FREAD_STR(headerNameBuf);
FREAD(size);
FREAD_STR(headerNameBuf, size);
cacheEntry.header.Name = std::string(headerNameBuf);
FREAD(cacheEntry.header.CRC1);
FREAD(cacheEntry.header.CRC2);
// (partial) settings
FREAD_STR(goodNameBuf);
FREAD_STR(md5Buf);
FREAD(size);
FREAD_STR(goodNameBuf, size);
FREAD(size);
FREAD_STR(md5Buf, size);
cacheEntry.settings.GoodName = std::string(goodNameBuf);
cacheEntry.settings.MD5 = std::string(md5Buf);
@@ -148,6 +171,7 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
char headerNameBuf[ROMHEADER_NAME_LEN];
char goodNameBuf[GOODNAME_LEN];
char md5Buf[MD5_LEN];
uint32_t size;
l_CacheEntry cacheEntry;
// only save cache when the entries have changed
@@ -167,12 +191,13 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
// write each entry in the file
#define FWRITE(x) outputStream.write((char*)&x, sizeof(x))
#define FWRITE_STR(x) outputStream.write((char*)x, sizeof(x))
#define FWRITE_STR(x, y) outputStream.write((char*)x, y)
for (auto iter = l_CacheEntries.cbegin(); iter != l_CacheEntries.end(); iter++)
{
cacheEntry = (*iter);
// reset buffers
size = 0;
memset(fileNameBuf, 0, sizeof(fileNameBuf));
memset(headerNameBuf, 0, sizeof(headerNameBuf));
memset(goodNameBuf, 0, sizeof(goodNameBuf));
@@ -185,15 +210,25 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
strncpy(md5Buf, cacheEntry.settings.MD5.c_str(), sizeof(md5Buf));
// file info
FWRITE_STR(fileNameBuf);
size = cacheEntry.fileName.wstring().size() * sizeof(wchar_t);
FWRITE(size);
FWRITE_STR(fileNameBuf, size);
FWRITE(cacheEntry.fileTime);
// type
FWRITE(cacheEntry.type);
// header
FWRITE_STR(headerNameBuf);
size = cacheEntry.header.Name.size();
FWRITE(size);
FWRITE_STR(headerNameBuf, size);
FWRITE(cacheEntry.header.CRC1);
FWRITE(cacheEntry.header.CRC2);
// (partial) settings
FWRITE_STR(goodNameBuf);
FWRITE_STR(md5Buf);
size = cacheEntry.settings.GoodName.size();
FWRITE(size);
FWRITE_STR(goodNameBuf, size);
size = cacheEntry.settings.MD5.size();
FWRITE(size);
FWRITE_STR(md5Buf, size);
}
#undef FWRITE
#undef FWRITE_STR
@@ -207,7 +242,7 @@ bool CoreHasRomHeaderAndSettingsCached(std::filesystem::path file)
return get_cache_entry_iter(file) != l_CacheEntries.end();
}
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader& header, CoreRomSettings& settings)
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType& type, CoreRomHeader& header, CoreRomSettings& settings)
{
auto iter = get_cache_entry_iter(file);
if (iter == l_CacheEntries.end())
@@ -215,12 +250,13 @@ bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
return false;
}
type = (*iter).type;
header = (*iter).header;
settings = (*iter).settings;
return true;
}
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader header, CoreRomSettings settings)
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings)
{
l_CacheEntry cacheEntry;
@@ -238,6 +274,7 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
cacheEntry.fileName = file;
cacheEntry.fileTime = osal_files_get_file_time(file);
cacheEntry.type = type;
cacheEntry.header = header;
cacheEntry.settings = settings;
@@ -245,3 +282,10 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
l_CacheEntriesChanged = true;
return true;
}
bool CoreClearRomHeaderAndSettingsCache(void)
{
l_CacheEntries.clear();
l_CacheEntriesChanged = true;
return true;
}
@@ -12,6 +12,7 @@
#include <filesystem>
#include "Rom.hpp"
#include "RomHeader.hpp"
#include "RomSettings.hpp"
@@ -30,10 +31,14 @@ bool CoreHasRomHeaderAndSettingsCached(std::filesystem::path file);
// returns whether retrieving the rom header & settings
// for given filename succeeds
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader& header, CoreRomSettings& settings);
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType& type, CoreRomHeader& header, CoreRomSettings& settings);
// returns whether adding cached rom header & settings
// for given filename succeeds
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader header, CoreRomSettings settings);
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
// returns whether clearing rom header & settings cache
// succeeds
bool CoreClearRomHeaderAndSettingsCache(void);
#endif // CORE_CACHEDROMHEADERANDSETTINGS_HPP
+17 -3
View File
@@ -9,13 +9,14 @@
*/
#define CORE_INTERNAL
#include "Core.hpp"
#include "ConvertStringEncoding.hpp"
//
// Local Variables
//
static bool l_SetupCallbacks = false;
static std::function<void(enum CoreDebugMessageType, std::string)> l_DebugCallbackFunc;
static std::function<void(enum CoreDebugMessageType, std::string, std::string)> l_DebugCallbackFunc;
//
// Internal Functions
@@ -28,7 +29,20 @@ void CoreDebugCallback(void* context, int level, const char* message)
return;
}
l_DebugCallbackFunc((CoreDebugMessageType)level, std::string(message));
std::string contextString((const char*)context);
std::string messageString(message);
// convert string encoding accordingly
if (messageString.starts_with("IS64:"))
{
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::EUC_JP);
}
else
{
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::Shift_JIS);
}
l_DebugCallbackFunc((CoreDebugMessageType)level, contextString, messageString);
}
void CoreStateCallback(void* context, m64p_core_param param, int value)
@@ -40,7 +54,7 @@ void CoreStateCallback(void* context, m64p_core_param param, int value)
// Exported Functions
//
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string)> debugCallbackFunc)
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc)
{
l_DebugCallbackFunc = debugCallbackFunc;
l_SetupCallbacks = true;
+1 -1
View File
@@ -32,6 +32,6 @@ enum class CoreDebugMessageType
Verbose = 5
};
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string)> debugCallbackFunc);
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc);
#endif // CORE_CALLBACK_HPP
+41
View File
@@ -717,6 +717,7 @@ bool CoreUpdateCheat(CoreCheat oldCheat, CoreCheat newCheat)
CoreRomHeader romHeader;
CoreRomSettings romSettings;
std::filesystem::path cheatFilePath;
CoreCheatOption cheatOption;
if (!CoreGetCurrentRomHeader(romHeader) ||
!CoreGetCurrentRomSettings(romSettings))
@@ -726,6 +727,23 @@ bool CoreUpdateCheat(CoreCheat oldCheat, CoreCheat newCheat)
cheatFilePath = get_user_cheat_file_path(romHeader, romSettings);
// copy over cheat settings when name has changed
if (oldCheat.Name != newCheat.Name)
{
CoreEnableCheat(newCheat, CoreIsCheatEnabled(oldCheat));
// only set option to new cheat when
// retrieving from old one succeeds
if (CoreGetCheatOption(oldCheat, cheatOption))
{
CoreSetCheatOption(newCheat, cheatOption);
}
// reset old cheat settings
CoreEnableCheat(oldCheat, false);
CoreResetCheatOption(oldCheat);
}
// try to find old cheat in user cheats,
// when it isnt found, it's most likely a system cheat
auto iter = find_user_cheat_using_name(oldCheat.Name);
@@ -892,6 +910,29 @@ bool CoreGetCheatOption(CoreCheat cheat, CoreCheatOption& option)
return false;
}
bool CoreResetCheatOption(CoreCheat cheat)
{
CoreRomSettings romSettings;
std::string settingSection;
std::string settingKey;
if (!cheat.HasOptions)
{
return false;
}
if (!CoreGetCurrentRomSettings(romSettings))
{
return false;
}
settingSection = romSettings.MD5 + " Cheats";
settingKey = "Cheat \"" + cheat.Name + "\" Option";
CoreSettingsSetValue(settingSection, settingKey, -1);
return true;
}
bool CoreApplyCheats(void)
{
std::string error;
+3
View File
@@ -136,6 +136,9 @@ bool CoreSetCheatOption(CoreCheat cheat, CoreCheatOption option);
// attempts to retrieve the currently's set cheat's option
bool CoreGetCheatOption(CoreCheat cheat, CoreCheatOption& option);
// attempts to reset the cheat option
bool CoreResetCheatOption(CoreCheat cheat);
// attempts to apply the enabled cheats to the currently opened ROM
bool CoreApplyCheats(void);
+1 -1
View File
@@ -13,7 +13,7 @@
#define CORE_VERSION "${GIT_VERSION}"
#ifndef PORTABLE_INSTALL
#define CORE_INSTAlL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#define CORE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#endif // PORTABLE_INSTALL
#endif // CORE_CONFIG_HPP
+78
View File
@@ -0,0 +1,78 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define CORE_INTERNAL
#include "ConvertStringEncoding.hpp"
#include "Error.hpp"
#include <string.h>
#include <string>
#include <iconv.h>
//
// Exported Functions
//
std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encoding)
{
std::string error;
std::string encodingString;
iconv_t cd;
char inputBuf[256] = {0};
char outputBuf[256] = {0};
char* inputBufPtr = (char*)str.c_str();
char* outputBufPtr = outputBuf;
size_t inputBufSize = str.size();
size_t outputBufSize = sizeof(outputBuf);
if (encoding == CoreStringEncoding::EUC_JP)
{
encodingString = "EUC-JP";
}
else
{
encodingString = "Shift_JIS";
}
cd = iconv_open("UTF-8//TRANSLIT//IGNORE", encodingString.c_str());
if (cd == (iconv_t)-1)
{
error = "CoreConvertStringEncoding Failed: ";
error += "iconv_open Failed: ";
error += errno;
CoreSetError(error);
return str;
}
size_t ret = iconv(cd, &inputBufPtr, &inputBufSize, &outputBufPtr, &outputBufSize);
if (ret == -1)
{
error = "CoreConvertStringEncoding Failed: ";
error += "iconv Failed: ";
error += errno;
CoreSetError(error);
// reset iconv
iconv(cd, nullptr, nullptr, nullptr, nullptr);
iconv_close(cd);
return str;
}
// reset iconv
iconv(cd, nullptr, nullptr, nullptr, nullptr);
iconv_close(cd);
return std::string(outputBuf);
}
+27
View File
@@ -0,0 +1,27 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef CORE_CONVERTSTRINGENCODING_HPP
#define CORE_CONVERTSTRINGENCODING_HPP
#ifdef CORE_INTERNAL
#include <string>
enum class CoreStringEncoding : int
{
EUC_JP = 0,
Shift_JIS = 1
};
// attempts to convert the string (which uses encoding) to UTF-8,
// on failure, returns original string
std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encoding);
#endif // CORE_INTERNAL
#endif // CORE_CONVERTSTRINGENCODING_HPP
+27 -10
View File
@@ -9,35 +9,40 @@
*/
#define CORE_INTERNAL
#include "Core.hpp"
#ifdef DISCORD_RPC
#include "DiscordRpc.hpp"
#endif // DISCORD_RPC
#include "osal/osal_dynlib.hpp"
#include "m64p/Api.hpp"
#include "m64p/api/version.h"
#include <filesystem>
#include <string>
#include <cstring>
//
// Local Variables
//
static osal_dynlib_lib_handle l_CoreLibHandle;
static char l_CoreContextString[20];
//
// Local Functions
//
std::string find_core_lib(void)
std::filesystem::path find_core_lib(void)
{
for (const auto& entry : std::filesystem::recursive_directory_iterator(CoreGetCoreDirectory()))
{
std::string path = entry.path().string();
if (path.ends_with(OSAL_DYNLIB_LIB_EXT_STR))
std::filesystem::path path = entry.path();
if (path.has_extension() &&
path.extension() == OSAL_DYNLIB_LIB_EXT_STR)
{
return path;
}
}
return std::string();
return std::filesystem::path();
}
bool config_override_user_dirs(void)
@@ -74,11 +79,14 @@ bool config_override_user_dirs(void)
bool CoreInit(void)
{
std::string error;
std::string core_file;
m64p_error m64p_ret;
std::string error;
std::filesystem::path core_file;
m64p_error m64p_ret;
bool ret = false;
// initialize context string
std::strcpy(l_CoreContextString, "[CORE] ");
core_file = find_core_lib();
if (core_file.empty())
{
@@ -87,7 +95,7 @@ bool CoreInit(void)
return false;
}
l_CoreLibHandle = osal_dynlib_open(core_file.c_str());
l_CoreLibHandle = osal_dynlib_open(core_file);
if (l_CoreLibHandle == nullptr)
{
error = "osal_dynlib_open Failed: ";
@@ -112,7 +120,7 @@ bool CoreInit(void)
return false;
}
m64p_ret = m64p::Core.Startup(FRONTEND_API_VERSION, CoreGetUserConfigDirectory().string().c_str(), CoreGetSharedDataDirectory().string().c_str(), nullptr, CoreDebugCallback, nullptr, CoreStateCallback);
m64p_ret = m64p::Core.Startup(FRONTEND_API_VERSION, CoreGetUserConfigDirectory().string().c_str(), CoreGetSharedDataDirectory().string().c_str(), (void*)l_CoreContextString, CoreDebugCallback, nullptr, CoreStateCallback);
if (m64p_ret != M64ERR_SUCCESS)
{
error = "CoreInit M64P::Core.Startup() Failed: ";
@@ -153,6 +161,11 @@ bool CoreInit(void)
CoreReadRomHeaderAndSettingsCache();
#ifdef DISCORD_RPC
CoreDiscordRpcInit();
CoreDiscordRpcUpdate(false);
#endif // DISCORD_RPC
return true;
}
@@ -186,6 +199,10 @@ void CoreShutdown(void)
CoreSaveRomHeaderAndSettingsCache();
#ifdef DISCORD_RPC
CoreDiscordRpcShutdown();
#endif // DISCORD_RPC
m64p::Core.Unhook();
m64p::Config.Unhook();
+2
View File
@@ -22,8 +22,10 @@
#include "RomHeader.hpp"
#include "Callback.hpp"
#include "Plugins.hpp"
#include "Version.hpp"
#include "Cheats.hpp"
#include "Error.hpp"
#include "Unzip.hpp"
#include "Video.hpp"
#include "Key.hpp"
#include "Rom.hpp"
+6 -6
View File
@@ -8,9 +8,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Directories.hpp"
#include "Config.hpp"
#include "Error.hpp"
#include "Core.hpp"
#include "Config.hpp"
#include "m64p/Api.hpp"
#include <cstdio>
@@ -123,7 +123,7 @@ std::filesystem::path CoreGetCoreDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Core";
#else // Not Portable
directory = CORE_INSTAlL_PREFIX;
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Core";
#endif // PORTABLE_INSTALL
return directory;
@@ -135,7 +135,7 @@ std::filesystem::path CoreGetPluginDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Plugin";
#else // Not Portable
directory = CORE_INSTAlL_PREFIX;
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Plugin";
#endif // PORTABLE_INSTALL
return directory;
@@ -180,7 +180,7 @@ std::filesystem::path CoreGetDefaultSaveDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Save/Game";
#else // Not Portable
directory = CoreGetUserDataDirectory();
directory = CoreGetDefaultUserDataDirectory();
directory += "/Save/Game";
#endif // PORTABLE_INSTALL
return directory;
@@ -192,7 +192,7 @@ std::filesystem::path CoreGetDefaultSaveStateDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Save/State";
#else // Not Portable
directory = CoreGetUserDataDirectory();
directory = CoreGetDefaultUserDataDirectory();
directory += "/Save/State";
#endif // PORTABLE_INSTALL
return directory;
@@ -233,7 +233,7 @@ std::filesystem::path CoreGetSharedDataDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Data";
#else // Not Portable
directory = CORE_INSTAlL_PREFIX;
directory = CORE_INSTALL_PREFIX;
directory += "/share/RMG";
#endif // PORTABLE_INSTALL
return directory;
+87
View File
@@ -0,0 +1,87 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Settings/Settings.hpp"
#include "DiscordRpc.hpp"
#include "RomSettings.hpp"
#include "RomHeader.hpp"
#include <../3rdParty/discord-rpc/include/discord_rpc.h>
#include <cstring>
#include <ctime>
#include <algorithm>
//
// Exported Functions
//
void CoreDiscordRpcInit(void)
{
if (!CoreSettingsGetBoolValue(SettingsID::GUI_DiscordRpc))
{
return;
}
Discord_Initialize("801450412280119356", nullptr, 0, "");
}
void CoreDiscordRpcShutdown(void)
{
Discord_Shutdown();
}
void CoreDiscordRpcUpdate(bool inGame)
{
std::string smallImageKey;
std::string largeImageKey;
std::string details;
if (!CoreSettingsGetBoolValue(SettingsID::GUI_DiscordRpc))
{
return;
}
if (inGame)
{
CoreRomSettings romSettings;
CoreRomHeader romHeader;
// make sure we retrieve the rom settings & header
if (!CoreGetCurrentRomSettings(romSettings) ||
!CoreGetCurrentRomHeader(romHeader))
{
return;
}
smallImageKey = "rmg-icon";
largeImageKey = romHeader.Name;
details = romSettings.GoodName;
// replace ' ' with '_' and replace '&' with '_'
// also tolower the entire string
std::replace(largeImageKey.begin(),largeImageKey.end(),' ','_');
std::replace(largeImageKey.begin(),largeImageKey.end(),'&','_');
std::transform(largeImageKey.begin(), largeImageKey.end(), largeImageKey.begin(), ::tolower);
}
else
{
largeImageKey = "rmg-icon";
details = "Not in-game";
}
DiscordRichPresence discordPresence;
memset(&discordPresence, 0, sizeof(discordPresence));
discordPresence.smallImageKey = smallImageKey.c_str();
discordPresence.largeImageKey = largeImageKey.c_str();
discordPresence.largeImageText = "Rosalie's Mupen GUI";
discordPresence.details = details.c_str();
discordPresence.startTimestamp = time(nullptr);
Discord_UpdatePresence(&discordPresence);
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef CORE_DISCORDRPC_HPP
#define CORE_DISCORDRPC_HPP
// initializes the discord rpc library
void CoreDiscordRpcInit(void);
// shuts down the discord rpc library
void CoreDiscordRpcShutdown(void);
// updates the state of the discord rpc library
void CoreDiscordRpcUpdate(bool inGame);
#endif // CORE_DISCORDRPC_HPP
+19 -2
View File
@@ -16,6 +16,9 @@
#include "Cheats.hpp"
#include "Error.hpp"
#include "Rom.hpp"
#ifdef DISCORD_RPC
#include "DiscordRpc.hpp"
#endif // DISCORD_RPC
//
// Local Functions
@@ -123,8 +126,11 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
return false;
}
// set disk file in media loader
CoreMediaLoaderSetDiskFile(n64ddrom);
// set disk file in media loader when ROM is a cartridge
if (CoreGetRomType() == CoreRomType::Cartridge)
{
CoreMediaLoaderSetDiskFile(n64ddrom);
}
// apply core settings overlay
apply_coresettings_overlay();
@@ -132,6 +138,10 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
// apply game core settings overrides
apply_game_coresettings_overlay();
#ifdef DISCORD_RPC
CoreDiscordRpcUpdate(true);
#endif // DISCORD_RPC
ret = m64p::Core.DoCommand(M64CMD_EXECUTE, 0, nullptr);
if (ret != M64ERR_SUCCESS)
{
@@ -147,6 +157,13 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
// restore plugin settings
CoreApplyPluginSettings();
// reset media loader state
CoreResetMediaLoader();
#ifdef DISCORD_RPC
CoreDiscordRpcUpdate(false);
#endif // DISCORD_RPC
return ret == M64ERR_SUCCESS;
}
+7 -2
View File
@@ -139,7 +139,12 @@ bool CoreSetupMediaLoader(void)
return ret == M64ERR_SUCCESS;
}
void CoreMediaLoaderSetDiskFile(std::filesystem::path ddRom)
void CoreResetMediaLoader(void)
{
l_DdDiskFile = ddRom;
l_DdRomFile = "";
}
void CoreMediaLoaderSetDiskFile(std::filesystem::path disk)
{
l_DdDiskFile = disk;
}
+4 -1
View File
@@ -15,7 +15,10 @@
// sets up the medialoader
bool CoreSetupMediaLoader(void);
// resets media loader state
void CoreResetMediaLoader(void);
// sets the media loader disk file
void CoreMediaLoaderSetDiskFile(std::filesystem::path ddRom);
void CoreMediaLoaderSetDiskFile(std::filesystem::path disk);
#endif // CORE_MEDIALOADER_HPP
+34 -1
View File
@@ -7,7 +7,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define CORE_INTERNAL
#include "Plugins.hpp"
#include "Callback.hpp"
#include "Directories.hpp"
#include "Error.hpp"
#include "Emulation.hpp"
@@ -21,6 +23,7 @@
#include "m64p/Api.hpp"
#include <filesystem>
#include <cstring>
//
// Local Variables
@@ -28,6 +31,7 @@
static m64p::PluginApi l_Plugins[(int)CorePluginType::Input];
static std::string l_PluginFiles[(int)CorePluginType::Input];
static char l_PluginContext[(int)CorePluginType::Input][20];
//
// Local Functions
@@ -101,6 +105,32 @@ std::string get_plugin_type_name(CorePluginType type)
return name + " Plugin";
}
std::string get_plugin_context_name(CorePluginType type)
{
std::string name;
switch (type)
{
default:
name = "[UNKNOWN]";
break;
case CorePluginType::Rsp:
name = "[RSP] ";
break;
case CorePluginType::Gfx:
name = "[GFX] ";
break;
case CorePluginType::Audio:
name = "[AUDIO] ";
break;
case CorePluginType::Input:
name = "[INPUT] ";
break;
}
return name;
}
bool apply_plugin_settings(std::string pluginSettings[4])
{
std::string error;
@@ -121,6 +151,9 @@ bool apply_plugin_settings(std::string pluginSettings[4])
pluginType = (CorePluginType)(i + 1);
// copy context string to a c string using strcpy
std::strcpy(l_PluginContext[(int)pluginType], get_plugin_context_name(pluginType).c_str());
if (settingValue != l_PluginFiles[i])
{
plugin = &l_Plugins[i];
@@ -179,7 +212,7 @@ bool apply_plugin_settings(std::string pluginSettings[4])
}
// attempt to start plugin
ret = plugin->Startup(m64p::Core.GetHandle(), nullptr, nullptr);
ret = plugin->Startup(m64p::Core.GetHandle(), (void*)l_PluginContext[(int)pluginType], CoreDebugCallback);
if (ret != M64ERR_SUCCESS)
{
error = "apply_plugin_settings (";
+280 -27
View File
@@ -8,15 +8,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Rom.hpp"
#include "Directories.hpp"
#include "Error.hpp"
#include "MediaLoader.hpp"
#include "m64p/Api.hpp"
#include "RomSettings.hpp"
#include "Cheats.hpp"
#include "osal/osal_files.hpp"
#include <unzip.h>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
//
// Local Defines
@@ -28,31 +32,136 @@
// Local Variables
//
static bool l_HasRomOpen = false;
static bool l_HasRomOpen = false;
static bool l_HasDisk = false;
static bool l_HasExtractedDisk = false;
static std::filesystem::path l_ExtractedDiskPath;
//
// Local Functions
//
static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
static std::string to_lower_str(std::string str)
{
std::string resultString = str;
std::transform(resultString.begin(), resultString.end(), resultString.begin(),
[](unsigned char c)
{
return std::tolower(c);
}
);
return resultString;
}
static voidpf zlib_filefunc_open(voidpf opaque, const void* filename, int mode)
{
std::filesystem::path path = *(std::filesystem::path*)filename;
// we need a static filestream
static std::ifstream fileStream;
// attempt to open file
fileStream.open(path, std::ios::binary);
if (!fileStream.is_open())
{
return nullptr;
}
return (voidpf)&fileStream;
}
static uLong zlib_filefunc_read(voidpf opaque, voidpf stream, void* buf, uLong size)
{
std::ifstream* fileStream = (std::ifstream*)stream;
fileStream->read((char*)buf, size);
return fileStream->fail() ? 0 : size;
}
static ZPOS64_T zlib_filefunc_tell(voidpf opaque, voidpf stream)
{
std::ifstream* fileStream = (std::ifstream*)stream;
return fileStream->tellg();
}
static long zlib_filefunc_seek(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
{
std::ifstream* fileStream = (std::ifstream*)stream;
std::ios_base::seekdir seekOrigin;
switch (origin)
{
default:
return 0;
case ZLIB_FILEFUNC_SEEK_CUR:
seekOrigin = std::ios::cur;
break;
case ZLIB_FILEFUNC_SEEK_END:
seekOrigin = std::ios::end;
break;
case ZLIB_FILEFUNC_SEEK_SET:
seekOrigin = std::ios::beg;
break;
}
fileStream->seekg(offset, seekOrigin);
return fileStream->fail() ? -1 : 0;
}
static int zlib_filefunc_close(voidpf opaque, voidpf stream)
{
std::ifstream* fileStream = (std::ifstream*)stream;
fileStream->close();
return fileStream->fail() ? -1 : 0;
}
static int zlib_filefunc_testerror(voidpf opaque, voidpf stream)
{
return errno;
}
static bool read_zip_file(std::filesystem::path file, std::filesystem::path* extractedFileName, bool* isDisk, char** buf, int* size)
{
std::string error;
std::fstream fileStream;
int fileStreamLen;
char* fileStreamBuf;
unzFile zipFile;
unz_global_info zipInfo;
unzFile zipFile;
unz_global_info64 zipInfo;
zipFile = unzOpen(file.string().c_str());
zlib_filefunc64_def filefuncs;
filefuncs.zopen64_file = zlib_filefunc_open;
filefuncs.zread_file = zlib_filefunc_read;
filefuncs.zwrite_file = nullptr;
filefuncs.ztell64_file = zlib_filefunc_tell;
filefuncs.zseek64_file = zlib_filefunc_seek;
filefuncs.zclose_file = zlib_filefunc_close;
filefuncs.zerror_file = zlib_filefunc_testerror;
filefuncs.opaque = nullptr;
zipFile = unzOpen2_64((const void*)&file, &filefuncs);
if (zipFile == nullptr)
{
error = "read_zip_file: unzOpen Failed!";
if (errno == 0)
{
error = "read_zip_file: unzOpen Failed!";
}
else
{
error = "read_zip_file: unzOpen Failed: ";
error += "failed to open file: ";
error += strerror(errno);
error += " (";
error += std::to_string(errno);
error += ")";
}
CoreSetError(error);
return false;
}
if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
if (unzGetGlobalInfo64(zipFile, &zipInfo) != UNZ_OK)
{
error = "read_zip_file: unzGetGlobalInfo Failed!";
CoreSetError(error);
@@ -74,9 +183,13 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
// make sure file has supported file format,
// if it does, read it in memory
std::filesystem::path fileNamePath(fileName);
if (fileNamePath.extension() == ".z64" ||
fileNamePath.extension() == ".v64" ||
fileNamePath.extension() == ".n64")
std::string fileExtension = fileNamePath.has_extension() ? fileNamePath.extension().string() : "";
fileExtension = to_lower_str(fileExtension);
if (fileExtension == ".z64" ||
fileExtension == ".v64" ||
fileExtension == ".n64" ||
fileExtension == ".ndd" ||
fileExtension == ".d64")
{
char* buffer;
char* outBuffer;
@@ -148,8 +261,10 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
}
} while (bytes_read > 0);
*size = total_bytes_read;
*buf = outBuffer;
*size = total_bytes_read;
*buf = outBuffer;
*extractedFileName = fileNamePath;
*isDisk = (fileExtension == ".ndd" || fileExtension == ".d64");
unzCloseCurrentFile(zipFile);
unzClose(zipFile);
free(buffer);
@@ -180,17 +295,21 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
{
std::string error;
std::fstream fileStream;
int fileStreamLen;
char* fileStreamBuf;
std::string error;
std::ifstream fileStream;
int fileStreamLen;
char* fileStreamBuf;
// attempt to open file
fileStream.open(file);
fileStream.open(file, std::ios::binary);
if (!fileStream.is_open())
{
error = "read_raw_file Failed: ";
error += "failed to open file!";
error += "failed to open file: ";
error += strerror(errno);
error += " (";
error += std::to_string(errno);
error += ")";
CoreSetError(error);
return false;
}
@@ -222,6 +341,32 @@ static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
return true;
}
static bool write_file(std::filesystem::path file, char* buf, int size)
{
std::string error;
std::ofstream fileStream;
// attempt to open file
fileStream.open(file, std::ios::binary);
if (!fileStream.is_open())
{
error = "write_file Failed: ";
error += "failed to open file: ";
error += strerror(errno);
error += " (";
error += std::to_string(errno);
error += ")";
CoreSetError(error);
return false;
}
// write buffer to file
fileStream.write(buf, size);
fileStream.close();
return true;
}
//
// Exported Functions
//
@@ -230,8 +375,9 @@ bool CoreOpenRom(std::filesystem::path file)
{
std::string error;
m64p_error ret;
char* buf;
int buf_size;
char* buf = nullptr;
int buf_size = 0;
std::string file_extension;
if (!m64p::Core.IsHooked())
{
@@ -246,12 +392,67 @@ bool CoreOpenRom(std::filesystem::path file)
return false;
}
if (file.has_extension() && file.extension() == ".zip")
file_extension = file.has_extension() ? file.extension().string() : "";
file_extension = to_lower_str(file_extension);
if (file_extension == ".zip")
{
if (!read_zip_file(file, &buf, &buf_size))
std::filesystem::path extracted_file;
bool is_disk = false;
if (!read_zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
{
return false;
}
if (is_disk)
{
std::filesystem::path disk_file;
disk_file = CoreGetUserCacheDirectory();
disk_file += "/extracted_disks/";
disk_file += extracted_file.filename();
// attempt to create extraction directory
try
{
if (!std::filesystem::exists(disk_file.parent_path()))
{
if (!std::filesystem::create_directory(disk_file.parent_path()))
{
throw std::exception();
}
}
}
catch (...)
{
error = "CoreOpenRom Failed: ";
error += "Failed to create \"";
error += disk_file.parent_path().string();
error += "\"!";
CoreSetError(error);
return false;
}
// attempt to write temporary file
if (!write_file(disk_file, buf, buf_size))
{
return false;
}
CoreMediaLoaderSetDiskFile(disk_file);
l_ExtractedDiskPath = disk_file;
}
l_HasDisk = is_disk;
l_HasExtractedDisk = is_disk;
}
else if (file_extension == ".d64" ||
file_extension == ".ndd")
{
CoreMediaLoaderSetDiskFile(file);
l_HasDisk = true;
l_HasExtractedDisk = false;
}
else
{
@@ -259,17 +460,29 @@ bool CoreOpenRom(std::filesystem::path file)
{
return false;
}
l_HasDisk = false;
l_HasExtractedDisk = false;
}
if (l_HasDisk)
{
ret = m64p::Core.DoCommand(M64CMD_DISK_OPEN, 0, nullptr);
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_DISK_OPEN) Failed: ";
}
else
{
ret = m64p::Core.DoCommand(M64CMD_ROM_OPEN, buf_size, buf);
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
free(buf);
}
ret = m64p::Core.DoCommand(M64CMD_ROM_OPEN, buf_size, buf);
if (ret != M64ERR_SUCCESS)
{
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
free(buf);
l_HasRomOpen = (ret == M64ERR_SUCCESS);
if (l_HasRomOpen)
@@ -288,6 +501,11 @@ bool CoreHasRomOpen(void)
return l_HasRomOpen;
}
CoreRomType CoreGetRomType(void)
{
return l_HasDisk ? CoreRomType::Disk : CoreRomType::Cartridge;
}
bool CoreCloseRom(void)
{
std::string error;
@@ -311,10 +529,19 @@ bool CoreCloseRom(void)
return false;
}
ret = m64p::Core.DoCommand(M64CMD_ROM_CLOSE, 0, nullptr);
if (l_HasDisk)
{
ret = m64p::Core.DoCommand(M64CMD_DISK_CLOSE, 0, nullptr);
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_DISK_CLOSE) Failed: ";
}
else
{
ret = m64p::Core.DoCommand(M64CMD_ROM_CLOSE, 0, nullptr);
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_ROM_CLOSE) Failed: ";
}
if (ret != M64ERR_SUCCESS)
{
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_ROM_CLOSE) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
return false;
@@ -323,6 +550,32 @@ bool CoreCloseRom(void)
// clear default ROM settings
CoreClearCurrentDefaultRomSettings();
// if removing the temporary extracted disk file
// fails, then we shouldn't break the state of
// whether we currently have an open ROM/disk,
// so we can safely say the ROM/disk isn't open
// anymore here
l_HasRomOpen = false;
// attempt to clean temporary extracted disk file
if (l_HasExtractedDisk)
{
try
{
if (!std::filesystem::remove(l_ExtractedDiskPath))
{
throw std::exception();
}
}
catch (...)
{
error = "CoreCloseRom: Failed to remove \"";
error += l_ExtractedDiskPath.string();
error += "\"!";
CoreSetError(error);
return false;
}
}
return true;
}
+9
View File
@@ -12,12 +12,21 @@
#include <filesystem>
enum class CoreRomType
{
Cartridge = 0,
Disk = 1
};
// opens the given file as ROM
bool CoreOpenRom(std::filesystem::path file);
// returns whether core has a ROM opened
bool CoreHasRomOpen(void);
// returns the opened ROM's type
CoreRomType CoreGetRomType(void);
// closes ROM
bool CoreCloseRom(void);
+4 -1
View File
@@ -13,7 +13,9 @@
#include <arpa/inet.h>
#endif // _WIN32
#define CORE_INTERNAL
#include "RomHeader.hpp"
#include "ConvertStringEncoding.hpp"
#include "Emulation.hpp"
#include "m64p/Api.hpp"
#include "Error.hpp"
@@ -46,6 +48,7 @@ bool CoreGetCurrentRomHeader(CoreRomHeader& header)
header.CRC1 = ntohl(m64p_header.CRC1);
header.CRC2 = ntohl(m64p_header.CRC2);
header.CountryCode = m64p_header.Country_code;
header.Name = std::string((char*)m64p_header.Name);
header.Name = CoreConvertStringEncoding((char*)m64p_header.Name, CoreStringEncoding::Shift_JIS);
return true;
}
+4 -1
View File
@@ -7,13 +7,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define CORE_INTERNAL
#include "RomSettings.hpp"
#include "Emulation.hpp"
#include "RomHeader.hpp"
#include "m64p/Api.hpp"
#include "Error.hpp"
#include "Rom.hpp"
#include "Settings/Settings.hpp"
#include "ConvertStringEncoding.hpp"
//
// Local Variables
@@ -46,7 +49,7 @@ bool CoreGetCurrentRomSettings(CoreRomSettings& settings)
return false;
}
settings.GoodName = std::string(m64p_settings.goodname);
settings.GoodName = CoreConvertStringEncoding(m64p_settings.goodname, CoreStringEncoding::Shift_JIS);
settings.MD5 = std::string(m64p_settings.MD5);
settings.SaveType = m64p_settings.savetype;
settings.DisableExtraMem = m64p_settings.disableextramem;
+288 -63
View File
@@ -10,7 +10,7 @@
#include "Settings.hpp"
#include "Directories.hpp"
#include "Config.hpp"
#include "Version.hpp"
#include "m64p/Api.hpp"
#include "Error.hpp"
#include "m64p/api/m64p_types.h"
@@ -140,9 +140,6 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::GUI_SettingsDialogHeight:
setting = {SETTING_SECTION_GUI, "SettingsDialogHeight", 0};
break;
case SettingsID::GUI_AllowManualResizing:
setting = {SETTING_SECTION_GUI, "AllowManualResizing", true};
break;
case SettingsID::GUI_HideCursorInEmulation:
setting = {SETTING_SECTION_GUI, "HideCursorInEmulation", false};
break;
@@ -161,8 +158,44 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::GUI_AutomaticFullscreen:
setting = {SETTING_SECTION_GUI, "AutomaticFullscreen", false};
break;
case SettingsID::GUI_ShowVerboseLogMessages:
setting = {SETTING_SECTION_GUI, "ShowVerboseLogMessages", false};
break;
case SettingsID::GUI_OnScreenDisplayEnabled:
setting = {SETTING_SECTION_GUI, "OnScreenDisplayEnabled", true};
break;
case SettingsID::GUI_OnScreenDisplayLocation:
setting = {SETTING_SECTION_GUI, "OnScreenDisplayLocation", 0};
break;
case SettingsID::GUI_OnScreenDisplayPaddingX:
setting = {SETTING_SECTION_GUI, "OnScreenDisplayPaddingX", 20};
break;
case SettingsID::GUI_OnScreenDisplayPaddingY:
setting = {SETTING_SECTION_GUI, "OnScreenDisplayPaddingY", 20};
break;
case SettingsID::GUI_OnScreenDisplayOpacity:
setting = {SETTING_SECTION_GUI, "OnScreenDisplayOpacity", 0.5f};
break;
case SettingsID::GUI_OnScreenDisplayDuration:
setting = {SETTING_SECTION_GUI, "OnScreenDisplayDuration", 3};
break;
case SettingsID::GUI_Toolbar:
setting = {SETTING_SECTION_GUI, "Toolbar", true};
break;
case SettingsID::GUI_StatusBar:
setting = {SETTING_SECTION_GUI, "StatusBar", true};
break;
case SettingsID::GUI_Theme:
setting = {SETTING_SECTION_GUI, "Theme", "Native"};
break;
case SettingsID::GUI_CheckForUpdates:
setting = {SETTING_SECTION_GUI, "CheckForUpdates", true};
break;
case SettingsID::GUI_DiscordRpc:
setting = {SETTING_SECTION_GUI, "DiscordRpc", true};
break;
case SettingsID::GUI_Version:
setting = {SETTING_SECTION_GUI, "Version", CORE_VERSION};
setting = {SETTING_SECTION_GUI, "Version", CoreGetVersion()};
break;
case SettingsID::Core_GFX_Plugin:
@@ -353,17 +386,14 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::KeyBinding_RemoveDuplicates:
setting = {SETTING_SECTION_KEYBIND, "RemoveDuplicates", true};
break;
case SettingsID::KeyBinding_OpenROM:
setting = {SETTING_SECTION_KEYBIND, "OpenROM", "Ctrl+O"};
case SettingsID::KeyBinding_StartROM:
setting = {SETTING_SECTION_KEYBIND, "StartROM", "Ctrl+O"};
break;
case SettingsID::KeyBinding_OpenCombo:
setting = {SETTING_SECTION_KEYBIND, "OpenCombo", "Ctrl+Shift+O"};
case SettingsID::KeyBinding_StartCombo:
setting = {SETTING_SECTION_KEYBIND, "StartCombo", "Ctrl+Shift+O"};
break;
case SettingsID::KeyBinding_StartEmulation:
setting = {SETTING_SECTION_KEYBIND, "StartEmulation", "F11"};
break;
case SettingsID::KeyBinding_EndEmulation:
setting = {SETTING_SECTION_KEYBIND, "EndEmulation", "F12"};
case SettingsID::KeyBinding_Shutdown:
setting = {SETTING_SECTION_KEYBIND, "Shutdown", "F12"};
break;
case SettingsID::KeyBinding_RefreshROMList:
setting = {SETTING_SECTION_KEYBIND, "RefreshROMList", "F5"};
@@ -380,15 +410,12 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::KeyBinding_Resume:
setting = {SETTING_SECTION_KEYBIND, "Resume", "F2"};
break;
case SettingsID::KeyBinding_GenerateBitmap:
setting = {SETTING_SECTION_KEYBIND, "GenerateBitmap", "F3"};
case SettingsID::KeyBinding_Screenshot:
setting = {SETTING_SECTION_KEYBIND, "Screenshot", "F3"};
break;
case SettingsID::KeyBinding_LimitFPS:
setting = {SETTING_SECTION_KEYBIND, "LimitFPS", "F4"};
break;
case SettingsID::KeyBinding_SwapDisk:
setting = {SETTING_SECTION_KEYBIND, "SwapDisk", "Ctrl+D"};
break;
case SettingsID::KeyBinding_SaveState:
setting = {SETTING_SECTION_KEYBIND, "SaveState", "F5"};
break;
@@ -407,6 +434,36 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::KeyBinding_GSButton:
setting = {SETTING_SECTION_KEYBIND, "GSButton", "F9"};
break;
case SettingsID::KeyBinding_SaveStateSlot0:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot0", "Ctrl+0"};
break;
case SettingsID::KeyBinding_SaveStateSlot1:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot1", "Ctrl+1"};
break;
case SettingsID::KeyBinding_SaveStateSlot2:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot2", "Ctrl+2"};
break;
case SettingsID::KeyBinding_SaveStateSlot3:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot3", "Ctrl+3"};
break;
case SettingsID::KeyBinding_SaveStateSlot4:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot4", "Ctrl+4"};
break;
case SettingsID::KeyBinding_SaveStateSlot5:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot5", "Ctrl+5"};
break;
case SettingsID::KeyBinding_SaveStateSlot6:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot6", "Ctrl+6"};
break;
case SettingsID::KeyBinding_SaveStateSlot7:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot7", "Ctrl+7"};
break;
case SettingsID::KeyBinding_SaveStateSlot8:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot8", "Ctrl+8"};
break;
case SettingsID::KeyBinding_SaveStateSlot9:
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot9", "Ctrl+9"};
break;
case SettingsID::KeyBinding_Fullscreen:
setting = {SETTING_SECTION_KEYBIND, "Fullscreen", "Alt+Return"};
break;
@@ -420,6 +477,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::RomBrowser_Geometry:
setting = {SETTING_SECTION_ROMBROWSER, "Geometry", ""};
break;
case SettingsID::RomBrowser_Maximized:
setting = {SETTING_SECTION_ROMBROWSER, "Maximized", false};
break;
case SettingsID::RomBrowser_Recursive:
setting = {SETTING_SECTION_ROMBROWSER, "Recursive", true};
break;
@@ -430,7 +490,28 @@ static l_Setting get_setting(SettingsID settingId)
setting = {SETTING_SECTION_ROMBROWSER, "Columns", std::vector<int>({0, 1, 2})};
break;
case SettingsID::RomBrowser_ColumnSizes:
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({0, 250, 1, 100, 2, 100})};
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({-1, -1, -1})};
break;
case SettingsID::RomBrowser_SortAfterSearch:
setting = {SETTING_SECTION_ROMBROWSER, "SortAfterSearch", true};
break;
case SettingsID::RomBrowser_ViewMode:
setting = {SETTING_SECTION_ROMBROWSER, "ViewMode", 0};
break;
case SettingsID::RomBrowser_ListViewSortSection:
setting = {SETTING_SECTION_ROMBROWSER, "ListViewSortSection", 0};
break;
case SettingsID::RomBrowser_ListViewSortOrder:
setting = {SETTING_SECTION_ROMBROWSER, "ListViewSortOrder", 0};
break;
case SettingsID::RomBrowser_GridViewIconWidth:
setting = {SETTING_SECTION_ROMBROWSER, "GridViewIconWidth", 180};
break;
case SettingsID::RomBrowser_GridViewIconHeight:
setting = {SETTING_SECTION_ROMBROWSER, "GridViewIconHeight", 126};
break;
case SettingsID::RomBrowser_GridViewUniformItemSizes:
setting = {SETTING_SECTION_ROMBROWSER, "GridViewUniformItemSizes", true};
break;
case SettingsID::Settings_HasForceUsedSetOnce:
@@ -462,7 +543,7 @@ static l_Setting get_setting(SettingsID settingId)
setting = {SETTING_SECTION_AUDIO, "Muted", false};
break;
case SettingsID::Audio_Synchronize:
setting = {SETTING_SECTION_AUDIO, "Synchronize", true};
setting = {SETTING_SECTION_AUDIO, "Synchronize", false};
break;
case SettingsID::Input_PluggedIn:
@@ -492,9 +573,6 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Input_RemoveDuplicateMappings:
setting = {"", "RemoveDuplicateMappings"};
break;
case SettingsID::Input_InvertAxis:
setting = {"", "InvertAxis"};
break;
case SettingsID::Input_A_InputType:
setting = {"", "A_InputType"};
break;
@@ -917,6 +995,94 @@ static bool config_option_default_set(std::string section, std::string key, m64p
return ret == M64ERR_SUCCESS;
}
static bool int_list_to_string(std::vector<int> intList, std::string& string)
{
for (int i = 0; i < intList.size(); i++)
{
int num = intList.at(i);
string += std::to_string(num);
// don't add seperator at end
// of the list
if (i < (intList.size() - 1))
{
string += ";";
}
}
return true;
}
static bool string_to_int_list(std::string string, std::vector<int>& intList)
{
std::string error;
// split string by ';'
// and append list with each item
std::stringstream value_str_stream(string);
std::string tmp_str;
while (std::getline(value_str_stream, tmp_str, ';'))
{
try
{
intList.emplace_back(std::stoi(tmp_str));
}
catch (...)
{
error = "string_to_int_list: std::stroi threw an exception!";
CoreSetError(error);
return false;
}
}
return true;
}
static bool string_list_to_string(std::vector<std::string> stringList, std::string& string)
{
std::string error;
for (int i = 0; i < stringList.size(); i++)
{
std::string str = stringList.at(i);
// ensure the string doesn't contain
// the separator character
if (str.find(";") != std::string::npos)
{
error = "string_list_to_string: string cannot contain ';'!";
CoreSetError(error);
return false;
}
string += str;
// don't add separator at end
// of the list
if (i < (stringList.size() - 1))
{
string += ";";
}
}
return true;
}
static bool string_to_string_list(std::string string, std::vector<std::string>& stringList)
{
std::string error;
// split string by ';'
// and append list with each item
std::stringstream value_str_stream(string);
std::string tmp_str;
while (std::getline(value_str_stream, tmp_str, ';'))
{
stringList.emplace_back(tmp_str);
}
return true;
}
//
// Exported Functions
//
@@ -951,7 +1117,7 @@ bool CoreSettingsUpgrade(void)
// we don't need to do anything
// when the core version and the settings version match
if (settingsVersion == CORE_VERSION)
if (settingsVersion == CoreGetVersion())
{
return true;
}
@@ -972,11 +1138,27 @@ bool CoreSettingsUpgrade(void)
CoreSettingsSetValue(SettingsID::Core_ScreenshotPath, CoreGetDefaultScreenshotDirectory());
}
#endif
}
if (settingsVersion == "v0.2.1" ||
settingsVersion == "v0.2.2" ||
settingsVersion == "v0.2.3")
{
// sadly when introducing the new RMG-Audio based on mupen64plus-audio-sdl
// 1) sync audio seems to cause crackling for some users
// 2) sync audio breaks the 'Limit FPS' option
// so to fix those issues, we'll disable the sync audio option
// if it's enabled
if (CoreSettingsGetBoolValue(SettingsID::Audio_Synchronize))
{
CoreSettingsSetValue(SettingsID::Audio_Synchronize, false);
}
}
// save core version
return CoreSettingsSetValue(SettingsID::GUI_Version, std::string(CORE_VERSION));
CoreSettingsSetValue(SettingsID::GUI_Version, CoreGetVersion());
CoreSettingsSave();
return true;
}
bool CoreSettingsSetupDefaults(void)
@@ -1015,7 +1197,7 @@ bool CoreSettingsSetupDefaults(void)
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_BOOL, &setting.DefaultValue.boolValue, setting.Description.c_str());
break;
case M64TYPE_FLOAT:
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_FLOAT, &setting.DefaultValue.intValue, setting.Description.c_str());
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_FLOAT, &setting.DefaultValue.floatValue, setting.Description.c_str());
break;
}
@@ -1099,10 +1281,19 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string value)
bool CoreSettingsSetValue(SettingsID settingId, std::vector<int> value)
{
std::string value_str;
for (const int& num : value)
if (!int_list_to_string(value, value_str))
{
value_str += std::to_string(num);
value_str += ";";
return false;
}
return CoreSettingsSetValue(settingId, value_str);
}
bool CoreSettingsSetValue(SettingsID settingId, std::vector<std::string> value)
{
std::string value_str;
if (!string_list_to_string(value, value_str))
{
return false;
}
return CoreSettingsSetValue(settingId, value_str);
}
@@ -1135,10 +1326,19 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::string
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<int> value)
{
std::string value_str;
for (const int& num : value)
if (!int_list_to_string(value, value_str))
{
value_str += std::to_string(num);
value_str += ";";
return false;
}
return CoreSettingsSetValue(settingId, section, value_str);
}
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<std::string> value)
{
std::string value_str;
if (!string_list_to_string(value, value_str))
{
return false;
}
return CoreSettingsSetValue(settingId, section, value_str);
}
@@ -1167,10 +1367,19 @@ bool CoreSettingsSetValue(std::string section, std::string key, std::string valu
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<int> value)
{
std::string value_str;
for (const int& num : value)
if (!int_list_to_string(value, value_str))
{
value_str += std::to_string(num);
value_str += ";";
return false;
}
return CoreSettingsSetValue(section, key, value_str);
}
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<std::string> value)
{
std::string value_str;
if (!string_list_to_string(value, value_str))
{
return false;
}
return CoreSettingsSetValue(section, key, value_str);
}
@@ -1243,6 +1452,12 @@ std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId)
return CoreSettingsGetIntListValue(settingId, setting.Section);
}
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId)
{
l_Setting setting = get_setting(settingId);
return CoreSettingsGetStringListValue(settingId, setting.Section);
}
int CoreSettingsGetIntValue(SettingsID settingId, std::string section)
{
l_Setting setting = get_setting(settingId);
@@ -1283,25 +1498,31 @@ std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId, std::string s
std::string value_str;
value_str = CoreSettingsGetStringValue(settingId, section);
// split string by ';'
// and append list with each item
std::stringstream value_str_stream(value_str);
std::string tmp_str;
while (std::getline(value_str_stream, tmp_str, ';'))
if (!string_to_int_list(value_str, value))
{
try
{
value.emplace_back(std::stoi(tmp_str));
}
catch (...)
{ // ignore exception
continue;
}
return std::vector<int>();
}
return value;
}
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId, std::string section)
{
l_Setting setting = get_setting(settingId);
std::vector<std::string> value;
std::string value_str;
value_str = CoreSettingsGetStringValue(settingId, section);
if (!string_to_string_list(value_str, value))
{
return std::vector<std::string>();
}
return value;
}
int CoreSettingsGetIntValue(std::string section, std::string key, int defaultValue)
{
int value = defaultValue;
@@ -1330,27 +1551,31 @@ std::string CoreSettingsGetStringValue(std::string section, std::string key)
return std::string(value);
}
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key, std::vector<int> defaultValue)
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key)
{
std::vector<int> value;
std::string value_str;
value_str = CoreSettingsGetStringValue(section, key);
// split string by ';'
// and append list with each item
std::stringstream value_str_stream(value_str);
std::string tmp_str;
while (std::getline(value_str_stream, tmp_str, ';'))
if (!string_to_int_list(value_str, value))
{
try
{
value.emplace_back(std::stoi(tmp_str));
}
catch (...)
{ // ignore exception
continue;
}
return std::vector<int>();
}
return value;
}
std::vector<std::string> CoreSettingsGetStringListValue(std::string section, std::string key)
{
std::vector<std::string> value;
std::string value_str;
value_str = CoreSettingsGetStringValue(section, key);
if (!string_to_string_list(value_str, value))
{
return std::vector<std::string>();
}
return value;
+14
View File
@@ -43,6 +43,8 @@ bool CoreSettingsSetValue(SettingsID settingId, float value);
bool CoreSettingsSetValue(SettingsID settingId, std::string value);
// sets setting as int list value
bool CoreSettingsSetValue(SettingsID settingId, std::vector<int> value);
// sets setting as string list value
bool CoreSettingsSetValue(SettingsID settingId, std::vector<std::string> value);
// sets setting in section as int value
bool CoreSettingsSetValue(SettingsID settingId, std::string section, int value);
@@ -54,6 +56,8 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string section, float value
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::string value);
// sets setting in section as int list value
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<int> value);
// sets setting as section as string list value
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<std::string> value);
#ifdef CORE_INTERNAL
// sets key in section as int value
@@ -66,6 +70,8 @@ bool CoreSettingsSetValue(std::string section, std::string key, float value);
bool CoreSettingsSetValue(std::string section, std::string key, std::string value);
// sets key in section as int list value
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<int> value);
// sets key in section as string list value
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<std::string> value);
#endif // CORE_INTERNAL
// retrieves default setting as int
@@ -78,6 +84,8 @@ float CoreSettingsGetDefaultFloatValue(SettingsID settingId);
std::string CoreSettingsGetDefaultStringValue(SettingsID settingId);
// retrieves default setting as int list
std::vector<int> CoreSettingsGetDefaultIntListValue(SettingsID settingId);
// retrieves default setting as string list
std::vector<std::string> CoreSettingsGetDefaultStringListValue(SettingsID settingId);
// retrieves setting as int
int CoreSettingsGetIntValue(SettingsID settingId);
@@ -89,6 +97,8 @@ float CoreSettingsGetFloatValue(SettingsID settingId);
std::string CoreSettingsGetStringValue(SettingsID settingId);
// retrieves setting as int list
std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId);
// retrieves setting as string list
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId);
// retrieves setting in section as int
int CoreSettingsGetIntValue(SettingsID settingId, std::string section);
@@ -100,6 +110,8 @@ float CoreSettingsGetFloatValue(SettingsID settingId, std::string section);
std::string CoreSettingsGetStringValue(SettingsID settingId, std::string section);
// retrieves setting in section as int list
std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId, std::string section);
// retrieves setting in section as string list
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId, std::string section);
#ifdef CORE_INTERNAL
// retrieves key in section as int
@@ -112,6 +124,8 @@ float CoreSettingsGetFloatValue(std::string section, std::string key, float defa
std::string CoreSettingsGetStringValue(std::string section, std::string key);
// retrieves key in section as int list
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key);
// retrieves key in section as string list
std::vector<std::string> CoreSettingsGetStringListValue(std::string section, std::string key);
#endif // CORE_INTERNAL
#endif // CORE_SETTINGS_HPP
+35 -9
View File
@@ -6,13 +6,24 @@ enum class SettingsID
// GUI Settings
GUI_SettingsDialogWidth = 0,
GUI_SettingsDialogHeight,
GUI_AllowManualResizing,
GUI_HideCursorInEmulation,
GUI_HideCursorInFullscreenEmulation,
GUI_StatusbarMessageDuration,
GUI_PauseEmulationOnFocusLoss,
GUI_ResumeEmulationOnFocus,
GUI_AutomaticFullscreen,
GUI_ShowVerboseLogMessages,
GUI_OnScreenDisplayEnabled,
GUI_OnScreenDisplayLocation,
GUI_OnScreenDisplayPaddingX,
GUI_OnScreenDisplayPaddingY,
GUI_OnScreenDisplayOpacity,
GUI_OnScreenDisplayDuration,
GUI_Toolbar,
GUI_StatusBar,
GUI_Theme,
GUI_CheckForUpdates,
GUI_DiscordRpc,
GUI_Version,
// Core Plugin Settings
@@ -87,35 +98,51 @@ enum class SettingsID
// GUI KeyBindings
KeyBinding_RemoveDuplicates,
KeyBinding_OpenROM,
KeyBinding_OpenCombo,
KeyBinding_StartEmulation,
KeyBinding_EndEmulation,
KeyBinding_StartROM,
KeyBinding_StartCombo,
KeyBinding_Shutdown,
KeyBinding_RefreshROMList,
KeyBinding_Exit,
KeyBinding_SoftReset,
KeyBinding_HardReset,
KeyBinding_Resume,
KeyBinding_GenerateBitmap,
KeyBinding_Screenshot,
KeyBinding_LimitFPS,
KeyBinding_SwapDisk,
KeyBinding_SaveState,
KeyBinding_SaveAs,
KeyBinding_LoadState,
KeyBinding_Load,
KeyBinding_Cheats,
KeyBinding_GSButton,
KeyBinding_SaveStateSlot0,
KeyBinding_SaveStateSlot1,
KeyBinding_SaveStateSlot2,
KeyBinding_SaveStateSlot3,
KeyBinding_SaveStateSlot4,
KeyBinding_SaveStateSlot5,
KeyBinding_SaveStateSlot6,
KeyBinding_SaveStateSlot7,
KeyBinding_SaveStateSlot8,
KeyBinding_SaveStateSlot9,
KeyBinding_Fullscreen,
KeyBinding_Settings,
// RomBrowser Settings
RomBrowser_Directory,
RomBrowser_Geometry,
RomBrowser_Maximized,
RomBrowser_Recursive,
RomBrowser_MaxItems,
RomBrowser_Columns,
RomBrowser_ColumnSizes,
RomBrowser_SortAfterSearch,
RomBrowser_ViewMode,
RomBrowser_ListViewSortSection,
RomBrowser_ListViewSortOrder,
RomBrowser_GridViewIconWidth,
RomBrowser_GridViewIconHeight,
RomBrowser_GridViewUniformItemSizes,
// Settings Settings
Settings_HasForceUsedSetOnce,
@@ -140,7 +167,6 @@ enum class SettingsID
Input_GameboyRom,
Input_GameboySave,
Input_RemoveDuplicateMappings,
Input_InvertAxis,
Input_A_InputType,
Input_A_Name,
Input_A_Data,
+169
View File
@@ -0,0 +1,169 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Unzip.hpp"
#include "Error.hpp"
#include <exception>
#include <filesystem>
#include <fstream>
#include <unzip.h>
//
// Local Defines
//
#define UNZIP_READ_SIZE 67108860 /* 64 MiB */
//
// Exported Functions
//
bool CoreUnzip(std::filesystem::path file, std::filesystem::path path)
{
std::string error;
unzFile zipFile;
unz_global_info zipInfo;
std::ofstream outputStream;
char* read_buffer = (char*)malloc(UNZIP_READ_SIZE);
size_t bytes_read = 0;
if (read_buffer == nullptr)
{
error = "CoreUnzip: malloc Failed!";
CoreSetError(error);
return false;
}
zipFile = unzOpen(file.string().c_str());
if (zipFile == nullptr)
{
free(read_buffer);
error = "CoreUnzip: unzOpen Failed!";
CoreSetError(error);
return false;
}
if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
{
free(read_buffer);
error = "CoreUnzip: unzGetGlobalInfo Failed!";
CoreSetError(error);
return false;
}
for (int i = 0; i < zipInfo.number_entry; i++)
{
unz_file_info fileInfo;
char fileName[PATH_MAX];
std::filesystem::path targetPath;
// ensure we can retrieve the current file info
if (unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, PATH_MAX, nullptr, 0, nullptr, 0) != UNZ_OK)
{
free(read_buffer);
unzClose(zipFile);
error = "CoreUnzip: unzGetCurrentFileInfo Failed!";
CoreSetError(error);
return false;
}
targetPath = path;
targetPath += "/";
targetPath += fileName;
if (targetPath.string().ends_with("/"))
{ // directory
try
{
if (!std::filesystem::is_directory(targetPath) &&
!std::filesystem::create_directory(targetPath))
{
throw std::exception();
}
}
catch (...)
{
free(read_buffer);
unzClose(zipFile);
error = "CoreUnzip: std::filesystem::create_directory(";
error += targetPath.string();
error += ") Failed!";
CoreSetError(error);
return false;
}
}
else
{ // file
if (unzOpenCurrentFile(zipFile) != UNZ_OK)
{
free(read_buffer);
unzClose(zipFile);
error = "CoreUnzip: unzOpenCurrentFile Failed!";
CoreSetError(error);
return false;
}
outputStream.open(targetPath, std::ios::trunc | std::ios::binary);
if (!outputStream.is_open())
{
free(read_buffer);
unzCloseCurrentFile(zipFile);
unzClose(zipFile);
error = "CoreUnzip: failed to open file!";
error += targetPath.string();
CoreSetError(error);
return false;
}
do
{
bytes_read = unzReadCurrentFile(zipFile, read_buffer, UNZIP_READ_SIZE);
if (bytes_read < 0)
{
free(read_buffer);
unzCloseCurrentFile(zipFile);
unzClose(zipFile);
error = "CoreUnzip: unzReadCurrentFile Failed!";
CoreSetError(error);
return false;
}
else
{ // write data to file
outputStream.write(read_buffer, bytes_read);
}
} while (bytes_read > 0);
outputStream.close();
unzCloseCurrentFile(zipFile);
}
// break when we've iterated over all entries
if ((i + 1) >= zipInfo.number_entry)
{
break;
}
// move to next file
if (unzGoToNextFile(zipFile) != UNZ_OK)
{
free(read_buffer);
unzClose(zipFile);
error = "CoreUnzip: unzGoToNextFile Failed!";
CoreSetError(error);
return false;
}
}
unzClose(zipFile);
free(read_buffer);
return true;
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef CORE_UNZIP_HPP
#define CORE_UNZIP_HPP
#include <filesystem>
// attempts to unzip the file to path
bool CoreUnzip(std::filesystem::path file, std::filesystem::path path);
#endif // CORE_UNZIP_HPP
@@ -7,10 +7,14 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
QTableView
#include "Version.hpp"
#include "Config.hpp"
//
// Exported Functions
//
std::string CoreGetVersion(void)
{
border: none;
color: #0096d3;
selection-color: #FFFFFF;
selection-background-color: #0096d3;
return std::string(CORE_VERSION);
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef CORE_VERSION_HPP
#define CORE_VERSION_HPP
#include <string>
// returns the current RMG-Core version (as string)
std::string CoreGetVersion(void);
#endif // CORE_VERSION_HPP
+3 -1
View File
@@ -168,7 +168,9 @@ typedef enum {
M64CMD_NETPLAY_GET_VERSION,
M64CMD_NETPLAY_CLOSE,
M64CMD_PIF_OPEN,
M64CMD_ROM_SET_SETTINGS
M64CMD_ROM_SET_SETTINGS,
M64CMD_DISK_OPEN,
M64CMD_DISK_CLOSE
} m64p_command;
typedef struct {
+3 -2
View File
@@ -11,6 +11,7 @@
#define OSAL_DYNLIB_HPP
#include <string>
#include <filesystem>
#ifdef _WIN32
#include <windows.h>
@@ -25,11 +26,11 @@ typedef void* osal_dynlib_lib_sym;
// returns library handle for given filename,
// return nullptr when invalid library
osal_dynlib_lib_handle osal_dynlib_open(const char *);
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path);
// retrieves symbol handle for given library
// handle, returns nullptr when not found
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle, const char *);
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle, const char* symbol);
// closes library handle
void osal_dynlib_close(osal_dynlib_lib_handle);
+4 -4
View File
@@ -11,14 +11,14 @@
#include <dlfcn.h>
osal_dynlib_lib_handle osal_dynlib_open(const char* file)
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path)
{
return dlopen(file, RTLD_LAZY);
return dlopen(path.string().c_str(), RTLD_LAZY);
}
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char *sym)
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char* symbol)
{
return dlsym(handle, sym);
return dlsym(handle, symbol);
}
void osal_dynlib_close(osal_dynlib_lib_handle handle)
+4 -4
View File
@@ -9,14 +9,14 @@
*/
#include "osal_dynlib.hpp"
osal_dynlib_lib_handle osal_dynlib_open(const char* file)
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path)
{
return LoadLibrary(file);
return LoadLibraryW(path.wstring().c_str());
}
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char *sym)
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char* symbol)
{
return GetProcAddress(handle, sym);
return GetProcAddress(handle, symbol);
}
void osal_dynlib_close(osal_dynlib_lib_handle handle)
+6 -4
View File
@@ -17,8 +17,9 @@ osal_files_file_time osal_files_get_file_time(std::filesystem::path file)
BOOL ret;
HANDLE file_handle;
FILETIME file_time;
ULARGE_INTEGER ularge_int;
file_handle = CreateFileA(file.string().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
file_handle = CreateFileW(file.wstring().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (file_handle == INVALID_HANDLE_VALUE)
{
return -1;
@@ -36,7 +37,8 @@ osal_files_file_time osal_files_get_file_time(std::filesystem::path file)
return -1;
}
// this is probably incorrect but it doesn't matter
// for our use-case
return file_time.dwLowDateTime + file_time.dwHighDateTime;
ularge_int.LowPart = file_time.dwLowDateTime;
ularge_int.HighPart = file_time.dwHighDateTime;
return ularge_int.QuadPart;
}
+5 -3
View File
@@ -8,7 +8,7 @@ set(CMAKE_AUTOUIC ON)
# disable lib prefix
set(CMAKE_SHARED_LIBRARY_PREFIX "")
find_package(Qt5 COMPONENTS Gui Widgets Core Svg REQUIRED)
find_package(Qt6 COMPONENTS Gui Widgets Core Svg REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
@@ -17,7 +17,9 @@ set(RMG_INPUT_SOURCES
UserInterface/Widget/ControllerWidget.ui
UserInterface/Widget/ControllerWidget.cpp
UserInterface/Widget/ControllerImageWidget.cpp
UserInterface/Widget/CustomButton.cpp
UserInterface/Widget/MappingButton.cpp
UserInterface/Widget/AddMappingButton.cpp
UserInterface/Widget/RemoveMappingButton.cpp
UserInterface/EventFilter.cpp
UserInterface/OptionsDialog.ui
UserInterface/OptionsDialog.cpp
@@ -41,4 +43,4 @@ target_include_directories(RMG-Input PRIVATE
${SDL2_INCLUDE_DIRS}
)
target_link_libraries(RMG-Input Qt5::Gui Qt5::Widgets Qt5::Svg)
target_link_libraries(RMG-Input Qt6::Gui Qt6::Widgets Qt6::Svg)
@@ -18,7 +18,7 @@
using namespace UserInterface;
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(parent)
{
this->setupUi(this);
this->setWindowIcon(QIcon(":Resource/RMG.png"));
@@ -111,9 +111,11 @@ void MainDialog::openInputDevice(QString deviceName, int deviceNum)
currentJoystick = SDL_JoystickOpen(deviceNum);
currentController = nullptr;
}
currentDeviceNum = deviceNum;
joystickId = SDL_JoystickGetDeviceInstanceID(deviceNum);
controllerWidget->SetCurrentJoystickID(joystickId);
controllerWidget->SetIsCurrentJoystickGameController(currentController != nullptr);
}
void MainDialog::closeInputDevice()
@@ -28,7 +28,7 @@ private:
QString deviceName;
int deviceNum;
bool operator== (inputDevice_t other)
bool operator== (inputDevice_t other) const
{
return other.deviceNum == deviceNum &&
other.deviceName == deviceName;
@@ -18,11 +18,13 @@ OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings) :
{
this->setupUi(this);
this->setIconsForEmulationInfoText();
this->controllerPakComboBox->setCurrentIndex(settings.ControllerPak);
this->gameboyRomLineEdit->setText(QString::fromStdString(settings.GameboyRom));
this->gameboySaveLineEdit->setText(QString::fromStdString(settings.GameboySave));
this->removeDuplicateMappingsCheckbox->setChecked(settings.RemoveDuplicateMappings);
this->invertAxisCheckBox->setChecked(settings.InvertAxis);
if (!CoreIsEmulationRunning() && !CoreIsEmulationPaused())
{
this->hideEmulationInfoText();
@@ -39,6 +41,21 @@ OptionsDialogSettings OptionsDialog::GetSettings()
return this->settings;
}
void OptionsDialog::setIconsForEmulationInfoText(void)
{
QLabel* labels[] = {
this->infoIconLabel_0
};
QIcon infoIcon = QIcon::fromTheme("information-line");
QPixmap infoIconPixmap = infoIcon.pixmap(16, 16);
for (QLabel* label : labels)
{
label->setPixmap(infoIconPixmap);
}
}
void OptionsDialog::hideEmulationInfoText(void)
{
QHBoxLayout *layouts[] = {this->emulationInfoLayout_1};
@@ -66,7 +83,6 @@ void OptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
this->settings.InvertAxis = this->invertAxisCheckBox->isChecked();
}
this->accept();
@@ -24,7 +24,6 @@ struct OptionsDialogSettings
// UI settings
bool RemoveDuplicateMappings = false;
bool InvertAxis = false;
};
namespace UserInterface
@@ -43,6 +42,7 @@ private:
bool hasSaved = false;
OptionsDialogSettings settings;
void setIconsForEmulationInfoText(void);
void hideEmulationInfoText(void);
private slots:
@@ -151,7 +151,7 @@
<item>
<layout class="QHBoxLayout" name="emulationInfoLayout_1">
<item>
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="infoIconLabel_0">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -162,7 +162,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="UIResources.qrc">:/Resource/Info.ico</pixmap>
<pixmap>:/Resource/Info.ico</pixmap>
</property>
<property name="scaledContents">
<bool>false</bool>
@@ -202,13 +202,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="invertAxisCheckBox">
<property name="text">
<string>Invert Axes Mapped To LRZ</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@@ -8,7 +8,7 @@
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
id="svg21"
sodipodi:docname="Controller.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
@@ -23,15 +23,17 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="0.28240146"
inkscape:cx="-426.69751"
inkscape:cy="3454.3023"
inkscape:zoom="0.070600365"
inkscape:cx="6019.7989"
inkscape:cy="1600.5583"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg21" />
inkscape:current-layer="layer2"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<path
id="Dark-Grey-Background"
serif:id="Dark Grey Background"
@@ -111,4 +113,39 @@
style="fill:#ec3f21"
id="circle18" />
</g>
</svg>
<g
id="layer2"
inkscape:label="Z-Button"
style="display:inline;opacity:1;stroke-width:1;stroke-dasharray:none;paint-order:markers stroke fill"
transform="matrix(50.366966,0,0,50.366966,3240.0678,-579.56452)"><g
id="layer2-0"
inkscape:label="Z-Button"
style="clip-rule:evenodd;display:inline;fill-rule:evenodd;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"><rect
style="clip-rule:evenodd;display:inline;opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.999999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
id="rect1917-0-4"
width="11.478539"
height="16.72587"
x="-32.517441"
y="86.256668"
ry="3.4675589"
inkscape:label="btnZ-outline"
class="theme-button"
ojd-button="Z" /><rect
style="display:inline;opacity:1;fill:#bcbdbf;fill-opacity:1;stroke:none;stroke-width:0.960842;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
id="rect1917-8"
width="10.956328"
height="16.177647"
x="-32.225891"
y="86.523468"
ry="3.3539019"
inkscape:label="btnZ"
class="theme-button"
ojd-button="Z" /><g
aria-label="Z"
style="font-style:normal;font-weight:normal;font-size:5.73478px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;clip-rule:evenodd;display:inline;opacity:1;fill:#56575b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.751267;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"
id="text1921-7"
transform="matrix(1.3310888,0,0,1.3310888,-67.459296,-40.853038)"><path
d="m 28.805176,99.685474 h 3.514231 v 0.652446 l -2.242948,2.71338 h 2.307352 v 0.81485 h -3.64304 v -0.65244 l 2.242948,-2.71338 h -2.178543 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#56575b;fill-opacity:1;stroke-width:0.751267;stroke-dasharray:none;paint-order:markers stroke fill"
id="path2008-2"
inkscape:connector-curvature="0" /></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

@@ -8,7 +8,7 @@
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
id="svg21"
sodipodi:docname="Controller_NoAnalogStick.svg"
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
@@ -23,15 +23,17 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="0.14120073"
inkscape:cx="2549.5619"
inkscape:cy="3325.0536"
inkscape:zoom="0.099843994"
inkscape:cx="2829.4141"
inkscape:cy="3475.4219"
inkscape:window-width="1920"
inkscape:window-height="1007"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg21" />
inkscape:current-layer="svg21"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<path
id="Dark-Grey-Background"
serif:id="Dark Grey Background"
@@ -101,4 +103,36 @@
style="fill:#ec3f21"
id="circle18" />
</g>
</svg>
<g
id="layer2"
inkscape:label="Z-Button"
style="display:inline;opacity:1;stroke-width:1;stroke-dasharray:none;paint-order:markers stroke fill"
transform="matrix(50.366966,0,0,50.366966,3240.0678,-579.56452)"><rect
style="clip-rule:evenodd;display:inline;opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.999999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
id="rect1917-0"
width="11.478539"
height="16.72587"
x="-32.517441"
y="86.256668"
ry="3.4675589"
inkscape:label="btnZ-outline"
class="theme-button"
ojd-button="Z" /><rect
style="display:inline;opacity:1;fill:#bcbdbf;fill-opacity:1;stroke:none;stroke-width:0.960842;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
id="rect1917"
width="10.956328"
height="16.177647"
x="-32.225891"
y="86.523468"
ry="3.3539019"
inkscape:label="btnZ"
class="theme-button"
ojd-button="Z" /><g
aria-label="Z"
style="font-style:normal;font-weight:normal;font-size:5.73478px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;clip-rule:evenodd;display:inline;opacity:1;fill:#56575b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.751267;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"
id="text1921"
transform="matrix(1.3310888,0,0,1.3310888,-67.459296,-40.853038)"><path
d="m 28.805176,99.685474 h 3.514231 v 0.652446 l -2.242948,2.71338 h 2.307352 v 0.81485 h -3.64304 v -0.65244 l 2.242948,-2.71338 h -2.178543 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#56575b;fill-opacity:1;stroke-width:0.751267;stroke-dasharray:none;paint-order:markers stroke fill"
id="path2008"
inkscape:connector-curvature="0" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="6939.9795"
height="6772.564"
viewBox="0 0 6939.9795 6772.564"
version="1.1"
xml:space="preserve"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
id="svg21"
sodipodi:docname="Controller_Pressed_ZTrigger.svg"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs25" /><sodipodi:namedview
id="namedview23"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="0.099843994"
inkscape:cx="2468.8516"
inkscape:cy="3856.0156"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg21"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<g
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
id="g5916"
transform="matrix(1.0882331,0,0,1.0882331,512.32815,1416.6572)"><circle
style="opacity:0.62;fill:#ececec;fill-rule:evenodd;stroke-width:0.280377"
id="path42"
cx="1267.6501"
cy="2546.3296"
r="180.5985" /></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -15,7 +15,7 @@
<file>Resource/Controller_Pressed_Start.svg</file>
<file>Resource/Controller_Pressed_LeftTrigger.svg</file>
<file>Resource/Controller_Pressed_RightTrigger.svg</file>
<file>Resource/Controller_Pressed_ZTrigger.svg</file>
<file>Resource/RMG.png</file>
<file>Resource/Info.ico</file>
</qresource>
</RCC>
@@ -0,0 +1,33 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "AddMappingButton.hpp"
#include "ControllerWidget.hpp"
#include "MappingButton.hpp"
using namespace UserInterface::Widget;
AddMappingButton::AddMappingButton(QWidget* parent) : QPushButton(parent)
{
}
AddMappingButton::~AddMappingButton()
{
}
void AddMappingButton::Initialize(ControllerWidget* widget, MappingButton* button)
{
this->controllerWidget = widget;
this->mappingButton = button;
connect(this, &QPushButton::released, [=]
{
emit this->controllerWidget->on_AddMappingButton_Released(this->mappingButton);
});
}
@@ -0,0 +1,43 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ADDMAPPINGBUTTON_HPP
#define ADDMAPPINGBUTTON_HPP
#include <QPushButton>
#include "common.hpp"
namespace UserInterface
{
namespace Widget
{
// we can't include ControllerWidget.hpp
// because that header includes this header,
// so forward-declare it to prevent issues
class ControllerWidget;
class MappingButton;
class AddMappingButton : public QPushButton
{
private:
ControllerWidget* controllerWidget = nullptr;
MappingButton* mappingButton = nullptr;
public:
AddMappingButton(QWidget* parent);
~AddMappingButton();
void Initialize(ControllerWidget* widget, MappingButton* button);
};
}
}
#endif // ADDMAPPINGBUTTON_HPP
@@ -125,6 +125,7 @@ void ControllerImageWidget::paintEvent(QPaintEvent *event)
{ N64ControllerButton::CButtonRight, ":Resource/Controller_Pressed_CButtonRight.svg" },
{ N64ControllerButton::LeftTrigger, ":Resource/Controller_Pressed_LeftTrigger.svg" },
{ N64ControllerButton::RightTrigger, ":Resource/Controller_Pressed_RightTrigger.svg" },
{ N64ControllerButton::ZTrigger, ":Resource/Controller_Pressed_ZTrigger.svg" }
};
static const QString baseImageUri = ":Resource/Controller_NoAnalogStick.svg";
@@ -58,6 +58,7 @@ ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) :
{ N64ControllerButton::CButtonRight, this->cbuttonRightButton },
{ N64ControllerButton::LeftTrigger, this->leftTriggerButton },
{ N64ControllerButton::RightTrigger, this->rightTriggerButton },
{ N64ControllerButton::ZTrigger, this->zTriggerButton }
});
this->joystickWidgetMappings.append(
@@ -90,7 +91,7 @@ ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) :
{ this->analogStickRightButton, SettingsID::Input_AnalogStickRight_InputType, SettingsID::Input_AnalogStickRight_Name, SettingsID::Input_AnalogStickRight_Data, SettingsID::Input_AnalogStickRight_ExtraData },
});
CustomButton* buttonList[] =
MappingButton* buttonList[] =
{
// dpad
this->dpadUpButton,
@@ -121,7 +122,7 @@ ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) :
this->setupButtonWidgets.append(button);
}
this->on_controllerPluggedCheckBox_toggled(false);
this->initializeButtons();
}
@@ -132,37 +133,50 @@ ControllerWidget::~ControllerWidget()
void ControllerWidget::initializeButtons()
{
CustomButton* buttonList[] =
struct
{
MappingButton* mappingButton;
AddMappingButton* addMappingButton;
RemoveMappingButton* removeMappingButton;
} mappingList[] =
{
// dpad
this->dpadUpButton,
this->dpadDownButton,
this->dpadLeftButton,
this->dpadRightButton,
{ this->dpadUpButton, this->dpadUpAddButton, this->dpadUpRemoveButton },
{ this->dpadDownButton, this->dpadDownAddButton, this->dpadDownRemoveButton },
{ this->dpadLeftButton, this->dpadLeftAddButton, this->dpadLeftRemoveButton },
{ this->dpadRightButton, this->dpadRightAddButton, this->dpadRightRemoveButton },
// analog stick
this->analogStickUpButton,
this->analogStickDownButton,
this->analogStickLeftButton,
this->analogStickRightButton,
{ this->analogStickUpButton, this->analogStickUpAddButton, this->analogStickUpRemoveButton },
{ this->analogStickDownButton, this->analogStickDownAddButton, this->analogStickDownRemoveButton },
{ this->analogStickLeftButton, this->analogStickLeftAddButton, this->analogStickLeftRemoveButton },
{ this->analogStickRightButton, this->analogStickRightAddButton, this->analogStickRightRemoveButton },
// cbuttons
this->cbuttonUpButton,
this->cbuttonDownButton,
this->cbuttonLeftButton,
this->cbuttonRightButton,
{ this->cbuttonUpButton, this->cbuttonUpAddButton, this->cbuttonUpRemoveButton },
{ this->cbuttonDownButton, this->cbuttonDownAddButton, this->cbuttonDownRemoveButton },
{ this->cbuttonLeftButton, this->cbuttonLeftAddButton, this->cbuttonLeftRemoveButton },
{ this->cbuttonRightButton, this->cbuttonRightAddButton, this->cbuttonRightRemoveButton },
// triggers
this->leftTriggerButton,
this->rightTriggerButton,
this->zTriggerButton,
{ this->leftTriggerButton, this->leftTriggerAddButton, this->leftTriggerRemoveButton },
{ this->rightTriggerButton, this->rightTriggerAddButton, this->rightTriggerRemoveButton },
{ this->zTriggerButton, this->zTriggerAddButton, this->zTriggerRemoveButton },
// buttons
this->aButton,
this->bButton,
this->startButton,
{ this->aButton, this->aAddButton, this->aRemoveButton },
{ this->bButton, this->bAddButton, this->bRemoveButton },
{ this->startButton, this->startAddButton, this->startRemoveButton },
};
for (auto& button : buttonList)
for (auto& mapping : mappingList)
{
button->Initialize(this);
button->setText(" ");
// initialize buttons
mapping.mappingButton->Initialize(this);
mapping.addMappingButton->Initialize(this, mapping.mappingButton);
mapping.removeMappingButton->Initialize(this, mapping.mappingButton);
// clear text & set icon
mapping.addMappingButton->setText("");
mapping.removeMappingButton->setText("");
mapping.addMappingButton->setIcon(QIcon::fromTheme("add-line"));
mapping.removeMappingButton->setIcon(QIcon::fromTheme("delete-back-line"));
}
}
@@ -211,7 +225,7 @@ void ControllerWidget::enableAllChildren()
}
}
void ControllerWidget::removeDuplicates(CustomButton* button)
void ControllerWidget::removeDuplicates(MappingButton* button)
{
std::string section = this->getCurrentSettingsSection().toStdString();
@@ -228,11 +242,20 @@ void ControllerWidget::removeDuplicates(CustomButton* button)
continue;
}
if ((buttonWidget->GetInputType() == button->GetInputType()) &&
(buttonWidget->GetInputData() == button->GetInputData()) &&
(buttonWidget->GetExtraInputData() == button->GetExtraInputData()))
std::vector<int> inputType;
std::vector<int> inputData;
std::vector<int> extraInputData;
inputType = button->GetInputType();
inputData = button->GetInputData();
extraInputData = button->GetExtraInputData();
for (int i = 0; i < inputType.size(); i++)
{
buttonWidget->Clear();
if (buttonWidget->HasInputData((InputType)inputType.at(i), inputData.at(i), extraInputData.at(i)))
{
buttonWidget->RemoveInputData((InputType)inputType.at(i), inputData.at(i), extraInputData.at(i));
}
}
}
}
@@ -292,6 +315,13 @@ void ControllerWidget::CheckInputDeviceSettings()
std::string deviceName = CoreSettingsGetStringValue(SettingsID::Input_DeviceName, section);
int deviceNum = CoreSettingsGetIntValue(SettingsID::Input_DeviceNum, section);
// do nothing when input device combobox
// is empty
if (this->inputDeviceComboBox->count() == 0)
{
return;
}
// clear (not found) devices first
int notFoundIndex = this->inputDeviceComboBox->findText("(not found)", Qt::MatchFlag::MatchEndsWith);
if (notFoundIndex != -1)
@@ -302,11 +332,11 @@ void ControllerWidget::CheckInputDeviceSettings()
int deviceNameIndex = this->inputDeviceComboBox->findText(QString::fromStdString(deviceName), Qt::MatchFlag::MatchStartsWith);
int deviceNumIndex = this->inputDeviceComboBox->findData(deviceNum);
if ((deviceNameIndex == deviceNumIndex) &&
(deviceNameIndex != -1))
if ((deviceNumIndex != -1) &&
(this->inputDeviceComboBox->itemText(deviceNumIndex).startsWith(QString::fromStdString(deviceName))))
{ // full match
this->inputDeviceComboBox->setCurrentIndex(deviceNameIndex);
this->inputDeviceComboBox->setCurrentIndex(deviceNumIndex);
}
else if (deviceNameIndex != -1)
{ // name only match
@@ -363,7 +393,7 @@ void ControllerWidget::on_profileComboBox_currentIndexChanged(int value)
// reload settings from section
this->LoadSettings(this->getCurrentSettingsSection());
// reload input device settings
CheckInputDeviceSettings();
this->CheckInputDeviceSettings();
}
void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value)
@@ -398,34 +428,37 @@ void ControllerWidget::on_controllerPluggedCheckBox_toggled(bool value)
QWidget* widgetList[] =
{
// dpad
this->dpadUpButton,
this->dpadDownButton,
this->dpadLeftButton,
this->dpadRightButton,
this->groupBox,
this->dpadUpButton, this->dpadUpAddButton, this->dpadUpRemoveButton,
this->dpadDownButton, this->dpadDownAddButton, this->dpadDownRemoveButton,
this->dpadLeftButton, this->dpadLeftAddButton, this->dpadLeftRemoveButton,
this->dpadRightButton, this->dpadRightAddButton, this->dpadRightRemoveButton,
// analog stick
this->analogStickUpButton,
this->analogStickDownButton,
this->analogStickLeftButton,
this->analogStickRightButton,
this->groupBox_2,
this->analogStickUpButton, this->analogStickUpAddButton, this->analogStickUpRemoveButton,
this->analogStickDownButton, this->analogStickDownAddButton, this->analogStickDownRemoveButton,
this->analogStickLeftButton, this->analogStickLeftAddButton, this->analogStickLeftRemoveButton,
this->analogStickRightButton, this->analogStickRightAddButton, this->analogStickRightRemoveButton,
// cbuttons
this->cbuttonUpButton,
this->cbuttonDownButton,
this->cbuttonLeftButton,
this->cbuttonRightButton,
this->groupBox_3,
this->cbuttonUpButton, this->cbuttonUpAddButton, this->cbuttonUpRemoveButton,
this->cbuttonDownButton, this->cbuttonDownAddButton, this->cbuttonDownRemoveButton,
this->cbuttonLeftButton, this->cbuttonLeftAddButton, this->cbuttonLeftRemoveButton,
this->cbuttonRightButton, this->cbuttonRightAddButton, this->cbuttonRightRemoveButton,
// triggers
this->leftTriggerButton,
this->rightTriggerButton,
this->zTriggerButton,
this->leftTriggerButton, this->leftTriggerAddButton, this->leftTriggerRemoveButton,
this->rightTriggerButton, this->rightTriggerAddButton, this->rightTriggerRemoveButton,
this->zTriggerButton, this->zTriggerAddButton, this->zTriggerRemoveButton,
// buttons
this->aButton,
this->bButton,
this->startButton,
this->groupBox_6,
this->aButton, this->aAddButton, this->aRemoveButton,
this->bButton, this->bAddButton, this->bRemoveButton,
this->startButton, this->startAddButton, this->startRemoveButton,
// misc UI elements
this->deadZoneSlider,
this->optionsButton,
this->profileComboBox,
this->removeProfileButton,
//this->setupButton,
this->resetButton,
this->inputDeviceComboBox,
this->inputDeviceRefreshButton
@@ -446,11 +479,15 @@ void ControllerWidget::on_removeProfileButton_clicked()
if (this->profileComboBox->currentIndex() == 0)
{
QMessageBox messageBox(this);
messageBox.setIcon(QMessageBox::Icon::Critical);
messageBox.setWindowTitle("Error");
messageBox.setText("Cannot remove main profile!");
messageBox.addButton(QMessageBox::Ok);
messageBox.exec();
messageBox.setIcon(QMessageBox::Icon::Warning);
messageBox.setText("Are you sure you want to reset the main profile?");
messageBox.addButton(QMessageBox::Yes);
messageBox.addButton(QMessageBox::No);
if (messageBox.exec() == QMessageBox::Yes)
{
this->SaveDefaultSettings();
this->LoadSettings(this->getCurrentSettingsSection());
}
return;
}
@@ -471,15 +508,6 @@ void ControllerWidget::on_removeProfileButton_clicked()
this->profileComboBox->setCurrentIndex(0);
}
void ControllerWidget::on_setupButton_clicked()
{
this->currentInSetup = true;
this->currentSetupButtonWidgetIndex = 0;
this->setupButtonWidgets.at(0)->setFocus(Qt::OtherFocusReason);
this->setupButtonWidgets.at(0)->click();
}
void ControllerWidget::on_resetButton_clicked()
{
this->LoadSettings();
@@ -497,7 +525,7 @@ void ControllerWidget::on_optionsButton_clicked()
}
}
void ControllerWidget::on_CustomButton_released(CustomButton* button)
void ControllerWidget::on_MappingButton_Released(MappingButton* button)
{
if (this->currentButton != nullptr)
{
@@ -512,11 +540,23 @@ void ControllerWidget::on_CustomButton_released(CustomButton* button)
this->disableAllChildren();
}
void ControllerWidget::on_CustomButton_TimerFinished(CustomButton* button)
void ControllerWidget::on_AddMappingButton_Released(MappingButton* button)
{
this->addMappingToButton = true;
button->click();
}
void ControllerWidget::on_RemoveMappingButton_Released(MappingButton* button)
{
button->RemoveLastInputData();
}
void ControllerWidget::on_MappingButton_TimerFinished(MappingButton* button)
{
if (this->currentButton == button)
{
this->currentButton = nullptr;
this->currentButton = nullptr;
this->addMappingToButton = false;
}
button->RestoreState();
@@ -524,11 +564,12 @@ void ControllerWidget::on_CustomButton_TimerFinished(CustomButton* button)
this->enableAllChildren();
}
void ControllerWidget::on_CustomButton_DataSet(CustomButton* button)
void ControllerWidget::on_MappingButton_DataSet(MappingButton* button)
{
this->enableAllChildren();
this->removeDuplicates(button);
this->currentButton = nullptr;
this->currentButton = nullptr;
this->addMappingToButton = false;
}
void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
@@ -549,6 +590,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
if ((event->type == SDL_CONTROLLERBUTTONDOWN) ||
(event->type == SDL_CONTROLLERBUTTONUP))
{ // gamepad button
if (!this->isCurrentJoystickGameController)
{
return;
}
joystickId = event->cbutton.which;
inputType = InputType::GamepadButton;
sdlButton = event->cbutton.button;
@@ -557,6 +603,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
}
else
{ // joystick button
if (this->isCurrentJoystickGameController)
{
return;
}
joystickId = event->jbutton.which;
inputType = InputType::JoystickButton;
sdlButton = event->jbutton.button;
@@ -575,12 +626,24 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
{
if (sdlButtonPressed)
{
this->currentButton->SetInputData(
inputType,
sdlButton,
0,
sdlButtonName
);
if (this->addMappingToButton)
{
this->currentButton->AddInputData(
inputType,
sdlButton,
0,
sdlButtonName
);
}
else
{
this->currentButton->SetInputData(
inputType,
sdlButton,
0,
sdlButtonName
);
}
}
break;
}
@@ -588,8 +651,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
// update controller button state
for (auto& button : this->buttonWidgetMappings)
{
if (button.buttonWidget->GetInputType() == inputType &&
button.buttonWidget->GetInputData() == sdlButton)
if (button.buttonWidget->HasInputData(inputType, sdlButton))
{
this->controllerImageWidget->SetButtonState(button.button, sdlButtonPressed);
}
@@ -598,8 +660,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
// update controller analog stick state
for (auto& joystick : this->joystickWidgetMappings)
{
if (joystick.buttonWidget->GetInputType() == inputType &&
joystick.buttonWidget->GetInputData() == sdlButton)
if (joystick.buttonWidget->HasInputData(inputType, sdlButton))
{
switch (joystick.direction)
{
@@ -643,6 +704,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
if (event->type == SDL_CONTROLLERAXISMOTION)
{ // gamepad axis
if (!this->isCurrentJoystickGameController)
{
return;
}
joystickId = event->caxis.which;
inputType = InputType::GamepadAxis;
sdlAxis = event->caxis.axis;
@@ -652,6 +718,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
}
else
{ // joystick axis
if (this->isCurrentJoystickGameController)
{
return;
}
joystickId = event->jaxis.which;
inputType = InputType::JoystickAxis;
sdlAxis = event->jaxis.axis;
@@ -677,24 +748,24 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
{
if (sdlAxisButtonPressed)
{
// invert axis for left, right & z trigger mappings
if (this->optionsDialogSettings.InvertAxis)
if (this->addMappingToButton)
{
if (this->currentButton == this->leftTriggerButton ||
this->currentButton == this->rightTriggerButton ||
this->currentButton == this->zTriggerButton)
{
sdlAxisDirection = (sdlAxisDirection == 1 ? 0 : 1);
sdlAxisName = "axis " + QString::number(sdlAxis);
sdlAxisName += sdlAxisDirection > 0 ? "+" : "-";
}
this->currentButton->AddInputData(
inputType,
sdlAxis,
sdlAxisDirection,
sdlAxisName
);
}
else
{
this->currentButton->SetInputData(
inputType,
sdlAxis,
sdlAxisDirection,
sdlAxisName
);
}
this->currentButton->SetInputData(
inputType,
sdlAxis,
sdlAxisDirection,
sdlAxisName
);
}
break;
}
@@ -702,9 +773,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
// update controller button state
for (auto& button : this->buttonWidgetMappings)
{
if (button.buttonWidget->GetInputType() == inputType &&
button.buttonWidget->GetInputData() == sdlAxis &&
button.buttonWidget->GetExtraInputData() == sdlAxisDirection)
if (button.buttonWidget->HasInputData(inputType, sdlAxis, sdlAxisDirection))
{
this->controllerImageWidget->SetButtonState(button.button, sdlAxisButtonPressed);
}
@@ -713,9 +782,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
// update controller analog stick state
for (auto& joystick : this->joystickWidgetMappings)
{
if (joystick.buttonWidget->GetInputType() == inputType &&
joystick.buttonWidget->GetInputData() == sdlAxis &&
joystick.buttonWidget->GetExtraInputData() == sdlAxisDirection)
if (joystick.buttonWidget->HasInputData(inputType, sdlAxis, sdlAxisDirection))
{
const int value = -(double)((double)sdlAxisValue / SDL_AXIS_PEAK * 100);
@@ -758,12 +825,24 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
{
if (sdlButtonPressed)
{
this->currentButton->SetInputData(
InputType::Keyboard,
sdlButton,
0,
SDL_GetScancodeName(sdlButton)
);
if (this->addMappingToButton)
{
this->currentButton->AddInputData(
InputType::Keyboard,
sdlButton,
0,
SDL_GetScancodeName(sdlButton)
);
}
else
{
this->currentButton->SetInputData(
InputType::Keyboard,
sdlButton,
0,
SDL_GetScancodeName(sdlButton)
);
}
}
break;
}
@@ -771,8 +850,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
// update controller button state
for (auto& button : this->buttonWidgetMappings)
{
if (button.buttonWidget->GetInputType() == InputType::Keyboard &&
button.buttonWidget->GetInputData() == sdlButton)
if (button.buttonWidget->HasInputData(InputType::Keyboard, sdlButton))
{
this->controllerImageWidget->SetButtonState(button.button, sdlButtonPressed);
}
@@ -781,8 +859,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
// update controller analog stick state
for (auto& joystick : this->joystickWidgetMappings)
{
if (joystick.buttonWidget->GetInputType() == InputType::Keyboard &&
joystick.buttonWidget->GetInputData() == sdlButton)
if (joystick.buttonWidget->HasInputData(InputType::Keyboard, sdlButton))
{
switch (joystick.direction)
{
@@ -897,20 +974,40 @@ void ControllerWidget::LoadSettings(QString sectionQString)
this->controllerPluggedCheckBox->setChecked(CoreSettingsGetBoolValue(SettingsID::Input_PluggedIn, section));
this->deadZoneSlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section));
this->optionsDialogSettings.RemoveDuplicateMappings = CoreSettingsGetBoolValue(SettingsID::Input_RemoveDuplicateMappings, section);
this->optionsDialogSettings.InvertAxis = CoreSettingsGetBoolValue(SettingsID::Input_InvertAxis, section);
this->optionsDialogSettings.ControllerPak = CoreSettingsGetIntValue(SettingsID::Input_Pak, section);
this->optionsDialogSettings.GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
this->optionsDialogSettings.GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
for (auto& buttonSetting : this->buttonSettingMappings)
{
enum InputType type = (InputType)CoreSettingsGetIntValue(buttonSetting.inputTypeSettingsId, section);
std::string name = CoreSettingsGetStringValue(buttonSetting.nameSettingsId, section);
int data = CoreSettingsGetIntValue(buttonSetting.dataSettingsId, section);
int extraData = CoreSettingsGetIntValue(buttonSetting.extraDataSettingsId, section);
buttonSetting.button->Clear();
buttonSetting.button->SetInputData(type, data, extraData, QString::fromStdString(name));
std::vector<int> types = CoreSettingsGetIntListValue(buttonSetting.inputTypeSettingsId, section);
std::vector<std::string> names = CoreSettingsGetStringListValue(buttonSetting.nameSettingsId, section);
std::vector<int> data = CoreSettingsGetIntListValue(buttonSetting.dataSettingsId, section);
std::vector<int> extraData = CoreSettingsGetIntListValue(buttonSetting.extraDataSettingsId, section);
int count = std::min(extraData.size(), std::min(types.size(), std::min(names.size(), data.size())));
if (count == 0)
{ // attempt to load old profile type
types.push_back(CoreSettingsGetIntValue(buttonSetting.inputTypeSettingsId, section));
names.push_back(CoreSettingsGetStringValue(buttonSetting.nameSettingsId, section));
data.push_back(CoreSettingsGetIntValue(buttonSetting.dataSettingsId, section));
extraData.push_back(CoreSettingsGetIntValue(buttonSetting.extraDataSettingsId, section));
count = 1;
}
// add all input data
for (int i = 0; i < count; i++)
{
buttonSetting.button->AddInputData((InputType)types[i], data[i], extraData[i], QString::fromStdString(names.at(i)));
}
}
// force refresh some UI elements
this->on_deadZoneSlider_valueChanged(this->deadZoneSlider->value());
this->on_controllerPluggedCheckBox_toggled(this->IsPluggedIn());
}
void ControllerWidget::SaveDefaultSettings()
@@ -928,14 +1025,13 @@ void ControllerWidget::SaveDefaultSettings()
CoreSettingsSetValue(SettingsID::Input_Deadzone, section, 9);
CoreSettingsSetValue(SettingsID::Input_Pak, section, 0);
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, true);
CoreSettingsSetValue(SettingsID::Input_InvertAxis, section, true);
for (auto& buttonSetting : this->buttonSettingMappings)
{
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, (int)InputType::Invalid);
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, std::string(" "));
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, 0);
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, 0);
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, std::vector<int>({ (int)InputType::Invalid }));
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, std::vector<std::string>({ std::string() }));
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, std::vector<int>({ 0 }));
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, std::vector<int>({ 0 }));
}
CoreSettingsSave();
@@ -962,12 +1058,11 @@ void ControllerWidget::SaveSettings()
CoreSettingsSetValue(SettingsID::Input_GameboyRom, section, this->optionsDialogSettings.GameboyRom);
CoreSettingsSetValue(SettingsID::Input_GameboySave, section, this->optionsDialogSettings.GameboySave);
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, this->optionsDialogSettings.RemoveDuplicateMappings);
CoreSettingsSetValue(SettingsID::Input_InvertAxis, section, this->optionsDialogSettings.InvertAxis);
for (auto& buttonSetting : this->buttonSettingMappings)
{
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, (int)buttonSetting.button->GetInputType());
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, buttonSetting.button->text().toStdString());
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, buttonSetting.button->GetInputType());
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, buttonSetting.button->GetInputText());
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, buttonSetting.button->GetInputData());
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, buttonSetting.button->GetExtraInputData());
}
@@ -980,3 +1075,8 @@ void ControllerWidget::SetCurrentJoystickID(SDL_JoystickID joystickId)
this->currentJoystickId = joystickId;
}
void ControllerWidget::SetIsCurrentJoystickGameController(bool isGameController)
{
this->isCurrentJoystickGameController = isGameController;
}
@@ -10,7 +10,7 @@
#ifndef CONTROLLERWIDGET_H
#define CONTROLLERWIDGET_H
#include "CustomButton.hpp"
#include "MappingButton.hpp"
#include "ControllerImageWidget.hpp"
#include "UserInterface/EventFilter.hpp"
@@ -39,23 +39,24 @@ private:
OptionsDialogSettings optionsDialogSettings;
QList<QString> inputDeviceNameList;
CustomButton* currentButton = nullptr;
MappingButton* currentButton = nullptr;
bool addMappingToButton = false;
struct buttonWidgetMapping
{
enum N64ControllerButton button;
CustomButton* buttonWidget;
MappingButton* buttonWidget;
};
struct axisWidgetMapping
{
enum InputAxisDirection direction;
CustomButton* buttonWidget;
MappingButton* buttonWidget;
};
struct buttonSettingMapping
{
CustomButton* button;
MappingButton* button;
SettingsID inputTypeSettingsId;
SettingsID nameSettingsId;
SettingsID dataSettingsId;
@@ -65,9 +66,7 @@ private:
QList<buttonWidgetMapping> buttonWidgetMappings;
QList<axisWidgetMapping> joystickWidgetMappings;
QList<buttonSettingMapping> buttonSettingMappings;
QList<CustomButton*> setupButtonWidgets;
int currentSetupButtonWidgetIndex = 0;
bool currentInSetup = false;
QList<MappingButton*> setupButtonWidgets;
void initializeButtons();
@@ -77,11 +76,12 @@ private:
void disableAllChildren();
void enableAllChildren();
void removeDuplicates(CustomButton* button);
void removeDuplicates(MappingButton* button);
QString getCurrentSettingsSection();
SDL_JoystickID currentJoystickId = -1;
SDL_JoystickID currentJoystickId = -1;
bool isCurrentJoystickGameController = false;
public:
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
@@ -105,6 +105,7 @@ public:
void SaveSettings();
void SetCurrentJoystickID(SDL_JoystickID joystickId);
void SetIsCurrentJoystickGameController(bool isGameController);
private slots:
void on_deadZoneSlider_valueChanged(int value);
@@ -117,15 +118,18 @@ private slots:
void on_controllerPluggedCheckBox_toggled(bool value);
void on_removeProfileButton_clicked();
void on_setupButton_clicked();
void on_resetButton_clicked();
void on_optionsButton_clicked();
public slots:
void on_CustomButton_released(CustomButton* button);
void on_CustomButton_TimerFinished(CustomButton* button);
void on_CustomButton_DataSet(CustomButton* button);
void on_MappingButton_Released(MappingButton* button);
void on_MappingButton_TimerFinished(MappingButton* button);
void on_MappingButton_DataSet(MappingButton* button);
void on_AddMappingButton_Released(MappingButton* button);
void on_RemoveMappingButton_Released(MappingButton* button);
void on_MainDialog_SdlEvent(SDL_Event* event);
void on_MainDialog_SdlEventPollFinished();
signals:
File diff suppressed because it is too large Load Diff
@@ -1,113 +0,0 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "CustomButton.hpp"
#include "ControllerWidget.hpp"
using namespace UserInterface::Widget;
CustomButton::CustomButton(QWidget* parent) : QPushButton(parent)
{
this->countDownTimer = new QTimer(this);
connect(this->countDownTimer, &QTimer::timeout, this, &CustomButton::on_countDownTimer_triggered);
}
CustomButton::~CustomButton()
{
}
void CustomButton::Initialize(QWidget* widget)
{
this->controllerWidget = (ControllerWidget*)widget;
connect(this, &QPushButton::released,
[=]
{
emit this->controllerWidget->on_CustomButton_released(this);
});
}
void CustomButton::Clear()
{
this->inputType = InputType::Invalid;
this->inputData = 0;
this->extraInputData = 0;
this->savedInputData = 0;
this->savedExtraInputData = 0;
this->setText(" ");
}
void CustomButton::StartTimer()
{
this->currentCountDownNum = 5;
this->on_countDownTimer_triggered();
this->countDownTimer->start(1000);
}
void CustomButton::StopTimer()
{
this->countDownTimer->stop();
}
void CustomButton::SetInputData(enum InputType type, int value, int extraValue, QString name)
{
this->inputType = type;
this->inputData = value;
this->extraInputData = extraValue;
this->setText(name);
this->StopTimer();
emit this->controllerWidget->on_CustomButton_DataSet(this);
}
enum InputType CustomButton::GetInputType()
{
return this->inputType;
}
int CustomButton::GetInputData()
{
return this->inputData;
}
int CustomButton::GetExtraInputData()
{
return this->extraInputData;
}
void CustomButton::SaveState()
{
this->savedInputType = this->inputType;
this->savedInputData = this->inputData;
this->savedExtraInputData = this->extraInputData;
this->savedText = this->text();
}
void CustomButton::RestoreState()
{
this->inputType = this->savedInputType;
this->inputData = this->savedInputData;
this->extraInputData = this->savedExtraInputData;
this->setText(this->savedText);
}
void CustomButton::on_countDownTimer_triggered()
{
this->setText(QString::number(this->currentCountDownNum));
if (this->currentCountDownNum == 0)
{
this->setText("");
this->currentCountDownNum = 5;
this->countDownTimer->stop();
emit this->controllerWidget->on_CustomButton_TimerFinished(this);
}
this->currentCountDownNum--;
}
@@ -1,67 +0,0 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef CUSTOMBUTTON_HPP
#define CUSTOMBUTTON_HPP
#include <QPushButton>
#include <QTimer>
#include "common.hpp"
namespace UserInterface
{
namespace Widget
{
// we can't include ControllerWidget.hpp
// because that header includes this header,
// so forward-declare it to prevent issues
class ControllerWidget;
class CustomButton : public QPushButton
{
private:
QTimer* countDownTimer = nullptr;
ControllerWidget* controllerWidget = nullptr;
int currentCountDownNum = 0;
enum InputType inputType = InputType::Invalid;
int inputData = 0;
int extraInputData = 0;
enum InputType savedInputType = InputType::Invalid;
int savedInputData = 0;
int savedExtraInputData = 0;
QString savedText;
public:
CustomButton(QWidget* parent);
~CustomButton();
void Initialize(QWidget* widget);
void Clear();
void StartTimer();
void StopTimer();
void SetInputData(enum InputType type, int value, int extraValue, QString name);
enum InputType GetInputType();
int GetInputData();
int GetExtraInputData();
void SaveState();
void RestoreState();
private slots:
void on_countDownTimer_triggered();
};
}
}
#endif // CUSTOMBUTTON_HPP
@@ -0,0 +1,248 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "MappingButton.hpp"
#include "ControllerWidget.hpp"
using namespace UserInterface::Widget;
MappingButton::MappingButton(QWidget* parent) : QPushButton(parent)
{
this->countDownTimer = new QTimer(this);
connect(this->countDownTimer, &QTimer::timeout, this, &MappingButton::on_countDownTimer_triggered);
}
MappingButton::~MappingButton()
{
}
void MappingButton::Initialize(ControllerWidget* widget)
{
this->controllerWidget = widget;
connect(this, &QPushButton::released, [=]
{
emit this->controllerWidget->on_MappingButton_Released(this);
});
this->setText(" ");
}
void MappingButton::Clear()
{
this->inputData.clear();
this->savedInputData.clear();
this->setText(" ");
}
void MappingButton::StartTimer()
{
this->currentCountDownNum = 5;
this->on_countDownTimer_triggered();
this->countDownTimer->start(1000);
}
void MappingButton::StopTimer()
{
this->countDownTimer->stop();
}
void MappingButton::SetInputData(enum InputType type, int value, int extraValue, QString name)
{
// don't add stub
if (name.simplified().isEmpty())
{
return;
}
this->inputData.clear();
this->inputData.push_back(
{
type,
value,
extraValue,
name
}
);
this->reloadText();
this->StopTimer();
emit this->controllerWidget->on_MappingButton_DataSet(this);
}
void MappingButton::AddInputData(enum InputType type, int value, int extraValue, QString name)
{
// don't add stub
if (name.simplified().isEmpty())
{
return;
}
if (!this->HasInputData(type, value, extraValue))
{
this->inputData.push_back(
{
type,
value,
extraValue,
name
}
);
}
this->reloadText();
this->StopTimer();
emit this->controllerWidget->on_MappingButton_DataSet(this);
}
void MappingButton::RemoveLastInputData(void)
{
if (!this->inputData.empty())
{
this->inputData.pop_back();
}
this->reloadText();
}
void MappingButton::RemoveInputData(InputType type, int value, int extraValue)
{
auto iter = this->getInputDataIter(type, value, extraValue);
if (iter == this->inputData.end())
{
return;
}
this->inputData.erase(iter);
this->reloadText();
}
bool MappingButton::HasInputData(enum InputType type, int value, int extraValue)
{
return this->getInputDataIter(type, value, extraValue) != this->inputData.end();
}
std::vector<int> MappingButton::GetInputType()
{
std::vector<int> inputTypeList;
for (const auto& data : this->inputData)
{
inputTypeList.push_back((int)data.Type);
}
return inputTypeList;
}
std::vector<int> MappingButton::GetInputData()
{
std::vector<int> inputDataList;
for (const auto& data : this->inputData)
{
inputDataList.push_back(data.Data);
}
return inputDataList;
}
std::vector<int> MappingButton::GetExtraInputData()
{
std::vector<int> extraInputDataList;
for (const auto& data : this->inputData)
{
extraInputDataList.push_back(data.ExtraData);
}
return extraInputDataList;
}
std::vector<std::string> MappingButton::GetInputText()
{
std::vector<std::string> inputTextList;
for (const auto& data : this->inputData)
{
inputTextList.push_back(data.Text.toStdString());
}
return inputTextList;
}
void MappingButton::SaveState()
{
this->savedInputData = this->inputData;
}
void MappingButton::RestoreState()
{
this->inputData = this->savedInputData;
this->reloadText();
}
void MappingButton::on_countDownTimer_triggered()
{
this->setText(QString::number(this->currentCountDownNum));
if (this->currentCountDownNum == 0)
{
this->setText("");
this->currentCountDownNum = 5;
this->countDownTimer->stop();
emit this->controllerWidget->on_MappingButton_TimerFinished(this);
}
this->currentCountDownNum--;
}
void MappingButton::reloadText()
{
QString text;
QFontMetrics fontMetrics(this->font());
int size = this->inputData.size();
for (int i = 0; i < size; i++)
{
text += this->inputData.at(i).Text;
// only add comma when
// not at the last item
if (i < (size - 1))
{
text += ", ";
}
}
QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, this->width());
// needed for spacing
if (elidedText.isEmpty())
{
elidedText = " ";
}
this->setToolTip(text);
this->setText(elidedText);
}
std::vector<MappingButtonInputDataType>::iterator MappingButton::getInputDataIter(InputType type, int value, int extraValue)
{
auto predicate = [type, value, extraValue](const auto& entry)
{
return entry.Type == type &&
(value == -1 || entry.Data == value) &&
(extraValue == -1 || entry.ExtraData == extraValue);
};
return std::find_if(this->inputData.begin(), this->inputData.end(), predicate);
}
@@ -0,0 +1,83 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MAPPINGBUTTON_HPP
#define MAPPINGBUTTON_HPP
#include <QPushButton>
#include <QTimer>
#include "common.hpp"
namespace UserInterface
{
namespace Widget
{
// we can't include ControllerWidget.hpp
// because that header includes this header,
// so forward-declare it to prevent issues
class ControllerWidget;
struct MappingButtonInputDataType
{
InputType Type;
int Data;
int ExtraData;
QString Text;
};
class MappingButton : public QPushButton
{
private:
QTimer* countDownTimer = nullptr;
ControllerWidget* controllerWidget = nullptr;
int currentCountDownNum = 0;
std::vector<MappingButtonInputDataType> inputData;
std::vector<MappingButtonInputDataType> savedInputData;
void reloadText();
std::vector<MappingButtonInputDataType>::iterator getInputDataIter(InputType type, int value, int extraValue);
public:
MappingButton(QWidget* parent);
~MappingButton();
void Initialize(ControllerWidget* widget);
void Clear();
void StartTimer();
void StopTimer();
void SetInputData(InputType type, int value, int extraValue, QString name);
void AddInputData(InputType type, int value, int extraValue, QString name);
void RemoveLastInputData(void);
void RemoveInputData(InputType type, int value, int extraValue);
bool HasInputData(InputType type, int value = -1, int extraValue = -1);
std::vector<int> GetInputType();
std::vector<int> GetInputData();
std::vector<int> GetExtraInputData();
std::vector<std::string> GetInputText();
void SaveState();
void RestoreState();
private slots:
void on_countDownTimer_triggered();
};
}
}
#endif // MAPPINGBUTTON_HPP
@@ -0,0 +1,33 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "RemoveMappingButton.hpp"
#include "ControllerWidget.hpp"
#include "MappingButton.hpp"
using namespace UserInterface::Widget;
RemoveMappingButton::RemoveMappingButton(QWidget* parent) : QPushButton(parent)
{
}
RemoveMappingButton::~RemoveMappingButton()
{
}
void RemoveMappingButton::Initialize(ControllerWidget* widget, MappingButton* button)
{
this->controllerWidget = widget;
this->mappingButton = button;
connect(this, &QPushButton::released, [=]
{
emit this->controllerWidget->on_RemoveMappingButton_Released(this->mappingButton);
});
}
@@ -0,0 +1,43 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef REMOVEMAPPINGBUTTON_HPP
#define REMOVEMAPPINGBUTTON_HPP
#include <QPushButton>
#include "common.hpp"
namespace UserInterface
{
namespace Widget
{
// we can't include ControllerWidget.hpp
// because that header includes this header,
// so forward-declare it to prevent issues
class ControllerWidget;
class MappingButton;
class RemoveMappingButton : public QPushButton
{
private:
ControllerWidget* controllerWidget = nullptr;
MappingButton* mappingButton = nullptr;
public:
RemoveMappingButton(QWidget* parent);
~RemoveMappingButton();
void Initialize(ControllerWidget* widget, MappingButton* button);
};
}
}
#endif // REMOVEMAPPINGBUTTON_HPP
+105 -71
View File
@@ -49,9 +49,10 @@
struct InputMapping
{
InputType Type = InputType::Invalid;
int Data = 0;
int ExtraData = 0;
std::vector<int> Type;
std::vector<int> Data;
std::vector<int> ExtraData;
int Count = 0;
};
struct InputProfile
@@ -122,9 +123,18 @@ static bool l_KeyboardState[SDL_NUM_SCANCODES];
static void load_inputmapping_settings(InputMapping* mapping, std::string section,
SettingsID inputTypeSettingsId, SettingsID dataSettingsId, SettingsID extraDataSettingsId)
{
mapping->Type = (InputType)CoreSettingsGetIntValue(inputTypeSettingsId, section);
mapping->Data = CoreSettingsGetIntValue(dataSettingsId, section);
mapping->ExtraData = CoreSettingsGetIntValue(extraDataSettingsId, section);
mapping->Type = CoreSettingsGetIntListValue(inputTypeSettingsId, section);
mapping->Data = CoreSettingsGetIntListValue(dataSettingsId, section);
mapping->ExtraData = CoreSettingsGetIntListValue(extraDataSettingsId, section);
mapping->Count = std::min(mapping->Type.size(), std::min(mapping->Data.size(), mapping->ExtraData.size()));
if (mapping->Count == 0)
{ // try to load old profile type
mapping->Type.push_back(CoreSettingsGetIntValue(inputTypeSettingsId, section));
mapping->Data.push_back(CoreSettingsGetIntValue(dataSettingsId, section));
mapping->ExtraData.push_back(CoreSettingsGetIntValue(extraDataSettingsId, section));
mapping->Count = 1;
}
}
static void load_settings(void)
@@ -286,88 +296,104 @@ static void close_controllers(void)
static int get_button_state(InputProfile* profile, InputMapping* inputMapping)
{
switch (inputMapping->Type)
int state = 0;
for (int i = 0; i < inputMapping->Count; i++)
{
case InputType::GamepadButton:
const int data = inputMapping->Data.at(i);
const int extraData = inputMapping->ExtraData.at(i);
switch ((InputType)inputMapping->Type[i])
{
return SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)inputMapping->Data);
};
case InputType::GamepadAxis:
{
int axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)inputMapping->Data);
return (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
};
case InputType::JoystickButton:
{
return SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
};
case InputType::JoystickAxis:
{
int axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
return (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
case InputType::GamepadButton:
{
state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
} break;
case InputType::GamepadAxis:
{
int axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)data);
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
} break;
case InputType::JoystickButton:
{
state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
} break;
case InputType::JoystickAxis:
{
int axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), data);
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
} break;
case InputType::Keyboard:
{
state |= l_KeyboardState[data] ? 1 : 0;
} break;
default:
break;
}
case InputType::Keyboard:
{
return l_KeyboardState[inputMapping->Data] ? 1 : 0;
};
default:
break;
}
return 0;
return state;
}
// returns axis input scaled to the range [-1, 1]
static double get_axis_state(InputProfile* profile, InputMapping* inputMapping, int direction, double value)
{
switch (inputMapping->Type)
{
case InputType::GamepadButton:
{
int buttonState = SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)inputMapping->Data);
return buttonState ? direction : value;
} break;
case InputType::GamepadAxis:
{
double axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)inputMapping->Data);
if (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)
{
axis_value = (axis_value / SDL_AXIS_PEAK);
axis_value = abs(axis_value) * direction;
return axis_value;
}
} break;
case InputType::JoystickButton:
{
int buttonState = SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
return buttonState ? direction : value;
} break;
case InputType::JoystickAxis:
{
double axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
if (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)
{
axis_value = (axis_value / SDL_AXIS_PEAK);
axis_value = abs(axis_value) * direction;
return axis_value;
}
} break;
case InputType::Keyboard:
{
return l_KeyboardState[inputMapping->Data] ? direction : value;
} break;
default:
break;
}
int state = 0;
return value;
for (int i = 0; i < inputMapping->Count; i++)
{
const int data = inputMapping->Data.at(i);
const int extraData = inputMapping->ExtraData.at(i);
switch ((InputType)inputMapping->Type[i])
{
case InputType::GamepadButton:
{
int buttonState = SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
state |= buttonState;
} break;
case InputType::GamepadAxis:
{
double axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)data);
if (extraData ? axis_value > 0 : axis_value < 0)
{
axis_value = (axis_value / SDL_AXIS_PEAK);
axis_value = abs(axis_value) * direction;
return axis_value;
}
} break;
case InputType::JoystickButton:
{
int buttonState = SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
state |= buttonState;
} break;
case InputType::JoystickAxis:
{
double axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), data);
if (extraData ? axis_value > 0 : axis_value < 0)
{
axis_value = (axis_value / SDL_AXIS_PEAK);
axis_value = abs(axis_value) * direction;
return axis_value;
}
} break;
case InputType::Keyboard:
{
state |= l_KeyboardState[data];
} break;
default:
break;
}
}
return state ? direction : value;
}
static double simulate_deadzone(double n64InputAxis, double maxAxis, int deadzone, double axisRange)
{
double axisAbsolute = std::abs(n64InputAxis);
if (axisAbsolute < deadzone)
if (axisAbsolute <= deadzone)
{
axisAbsolute = 0; // No input when inside deadzone
}
@@ -450,6 +476,8 @@ static unsigned char data_crc(unsigned char *data, int length)
void sdl_init()
{
std::filesystem::path gameControllerDbPath;
for (int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
{
if (!SDL_WasInit(subsystem))
@@ -457,6 +485,12 @@ void sdl_init()
SDL_InitSubSystem(subsystem);
}
}
gameControllerDbPath = CoreGetSharedDataDirectory();
gameControllerDbPath += "/gamecontrollerdb.txt";
// load mappings from file
SDL_GameControllerAddMappingsFromFile(gameControllerDbPath.string().c_str());
}
void sdl_quit()
+48 -6
View File
@@ -5,21 +5,37 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5 COMPONENTS Gui Widgets Core REQUIRED)
find_package(Qt6 COMPONENTS Gui Widgets Core OpenGL REQUIRED)
if (PORTABLE_INSTALL)
add_definitions(-DPORTABLE_INSTALL)
endif(PORTABLE_INSTALL)
if (UPDATER)
find_package(Qt6 COMPONENTS Network REQUIRED)
add_definitions(-DUPDATER)
endif(UPDATER)
if (DISCORD_RPC)
add_definitions(-DDISCORD_RPC)
endif(DISCORD_RPC)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
configure_file(Config.hpp.in Config.hpp)
set(RMG_SOURCES
UserInterface/MainWindow.cpp
UserInterface/MainWindow.ui
UserInterface/Widget/RomBrowserWidget.cpp
UserInterface/Widget/RomBrowserListViewWidget.cpp
UserInterface/Widget/RomBrowserGridViewWidget.cpp
UserInterface/Widget/RomBrowserLoadingWidget.cpp
UserInterface/Widget/RomBrowserEmptyWidget.cpp
UserInterface/Widget/RomBrowserEmptyWidget.ui
UserInterface/Widget/OGLWidget.cpp
UserInterface/Widget/KeybindButton.cpp
UserInterface/Dialog/SettingsDialog.cpp
UserInterface/Dialog/SettingsDialog.ui
UserInterface/Dialog/SettingsDialog.qrc
UserInterface/Dialog/CheatsDialog.cpp
UserInterface/Dialog/CheatsDialog.ui
UserInterface/Dialog/AddCheatDialog.cpp
@@ -30,6 +46,8 @@ set(RMG_SOURCES
UserInterface/Dialog/RomInfoDialog.ui
UserInterface/Dialog/AboutDialog.cpp
UserInterface/Dialog/AboutDialog.ui
UserInterface/Dialog/LogDialog.cpp
UserInterface/Dialog/LogDialog.ui
UserInterface/NoFocusDelegate.cpp
UserInterface/EventFilter.cpp
UserInterface/UIResources.rc
@@ -37,20 +55,38 @@ set(RMG_SOURCES
Thread/RomSearcherThread.cpp
Thread/EmulationThread.cpp
Utilities/QtKeyToSdl2Key.cpp
OnScreenDisplay.cpp
Callbacks.cpp
VidExt.cpp
main.cpp
)
if (UPDATER)
list(APPEND RMG_SOURCES
UserInterface/Dialog/UpdateDialog.cpp
UserInterface/Dialog/UpdateDialog.ui
UserInterface/Dialog/DownloadUpdateDialog.cpp
UserInterface/Dialog/DownloadUpdateDialog.ui
UserInterface/Dialog/InstallUpdateDialog.cpp
UserInterface/Dialog/InstallUpdateDialog.ui
)
endif(UPDATER)
set_source_files_properties(${IMGUI_SOURCES} PROPERTIES GENERATED TRUE)
list(APPEND RMG_SOURCES ${IMGUI_SOURCES})
if (CMAKE_BUILD_TYPE MATCHES Release)
add_executable(RMG WIN32 ${RMG_SOURCES})
else()
add_executable(RMG ${RMG_SOURCES})
endif()
add_dependencies(RMG
imgui
)
target_link_libraries(RMG
RMG-Core
${SDL2_LIBRARIES}
)
target_include_directories(RMG PRIVATE
@@ -58,6 +94,12 @@ target_include_directories(RMG PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../
${SDL2_INCLUDE_DIRS}
${IMGUI_DIR}
)
target_link_libraries(RMG Qt5::Gui Qt5::Widgets)
target_link_libraries(RMG Qt6::Gui Qt6::Widgets Qt6::OpenGL)
if (UPDATER)
target_link_libraries(RMG Qt6::Network)
endif(UPDATER)
+16 -2
View File
@@ -16,6 +16,7 @@
//
static CoreCallbacks* l_CoreCallbacks = nullptr;
static bool l_showVerboseMessages = false;
//
// Exported Functions
@@ -36,6 +37,8 @@ bool CoreCallbacks::Init(void)
// needed for Qt
qRegisterMetaType<CoreDebugMessageType>("CoreDebugMessageType");
this->LoadSettings();
l_CoreCallbacks = this;
return CoreSetupCallbacks(this->coreDebugCallback);
}
@@ -45,12 +48,23 @@ void CoreCallbacks::Stop(void)
l_CoreCallbacks = nullptr;
}
void CoreCallbacks::coreDebugCallback(CoreDebugMessageType type, std::string message)
void CoreCallbacks::LoadSettings(void)
{
l_showVerboseMessages = CoreSettingsGetBoolValue(SettingsID::GUI_ShowVerboseLogMessages);
}
void CoreCallbacks::coreDebugCallback(CoreDebugMessageType type, std::string context, std::string message)
{
if (l_CoreCallbacks == nullptr)
{
return;
}
emit l_CoreCallbacks->OnCoreDebugCallback(type, QString::fromStdString(message));
// only show verbose messages when enabled
if (!l_showVerboseMessages && type == CoreDebugMessageType::Verbose)
{
return;
}
emit l_CoreCallbacks->OnCoreDebugCallback(type, QString::fromStdString(context), QString::fromStdString(message));
}
+4 -2
View File
@@ -27,11 +27,13 @@ public:
bool Init(void);
void Stop(void);
void LoadSettings(void);
private:
static void coreDebugCallback(CoreDebugMessageType type, std::string message);
static void coreDebugCallback(CoreDebugMessageType type, std::string context, std::string message);
signals:
void OnCoreDebugCallback(CoreDebugMessageType type, QString message);
void OnCoreDebugCallback(CoreDebugMessageType type, QString context, QString message);
};
#endif // RMG_CALLBACKS_HPP
-7
View File
@@ -1,7 +0,0 @@
#ifndef CONFIG_HPP
#define CONFIG_HPP
#define WINDOW_TITLE "Rosalie's Mupen GUI (${GIT_VERSION})"
#define VERSION_STR "${GIT_VERSION}"
#endif // CONFIG_HPP
+166
View File
@@ -0,0 +1,166 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "OnScreenDisplay.hpp"
#include <RMG-Core/Core.hpp>
#include <imgui.h>
#include <backends/imgui_impl_opengl3.h>
#include <chrono>
//
// Local Variables
//
static bool l_Initialized = false;
static bool l_Enabled = false;
static bool l_RenderingPaused = false;
static std::chrono::time_point<std::chrono::high_resolution_clock> l_MessageTime;
static std::string l_Message;
static int l_MessagePosition = 1;
static float l_MessagePaddingX = 20.0f;
static float l_MessagePaddingY = 20.0f;
static float l_MessageOpacity = 1.0f;
static int l_MessageDuration = 3;
//
// Exported Functions
//
bool OnScreenDisplayInit(void)
{
if (l_Initialized)
{
return false;
}
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui::StyleColorsDark();
if (!ImGui_ImplOpenGL3_Init())
{
return false;
}
l_Initialized = true;
return true;
}
void OnScreenDisplayShutdown(void)
{
if (!l_Initialized)
{
return;
}
ImGui_ImplOpenGL3_Shutdown();
ImGui::DestroyContext();
l_Message = "";
l_Initialized = false;
l_RenderingPaused = false;
}
void OnScreenDisplayLoadSettings(void)
{
l_Enabled = CoreSettingsGetBoolValue(SettingsID::GUI_OnScreenDisplayEnabled);
l_MessagePosition = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayLocation);
l_MessagePaddingX = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayPaddingX);
l_MessagePaddingY = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayPaddingY);
l_MessageOpacity = CoreSettingsGetFloatValue(SettingsID::GUI_OnScreenDisplayOpacity);
l_MessageDuration = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayDuration);
}
bool OnScreenDisplaySetDisplaySize(int width, int height)
{
if (!l_Initialized)
{
return false;
}
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = nullptr;
io.DisplaySize = ImVec2((float)width, (float)height);
return true;
}
void OnScreenDisplaySetMessage(std::string message)
{
if (!l_Initialized)
{
return;
}
l_Message = message;
l_MessageTime = std::chrono::high_resolution_clock::now();
}
void OnScreenDisplayRender(void)
{
if (!l_Initialized || !l_Enabled || l_RenderingPaused || l_Message.empty())
{
return;
}
const auto currentTime = std::chrono::high_resolution_clock::now();
const int secondsPassed = std::chrono::duration_cast<std::chrono::seconds>(currentTime - l_MessageTime).count();
if (secondsPassed >= l_MessageDuration)
{
return;
}
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
ImGuiIO& io = ImGui::GetIO();
ImGui::SetNextWindowBgAlpha(l_MessageOpacity);
// right bottom = ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - 20.0f, io.DisplaySize.y - 20.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));
// right top = ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - 20.0f, 20.0f), ImGuiCond_Always, ImVec2(1.0f, 0));
// left bottom = ImGui::SetNextWindowPos(ImVec2(20.0f, io.DisplaySize.y - 20.0f), ImGuiCond_Always, ImVec2(0.0f, 1.0f));
// left top = ImGui::SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiCond_Always, ImVec2(0.0f, 0.0f));
switch (l_MessagePosition)
{
default:
case 0: // left bottom
ImGui::SetNextWindowPos(ImVec2(l_MessagePaddingX, io.DisplaySize.y - l_MessagePaddingY), ImGuiCond_Always, ImVec2(0.0f, 1.0f));
break;
case 1: // left top
ImGui::SetNextWindowPos(ImVec2(l_MessagePaddingX, l_MessagePaddingY), ImGuiCond_Always, ImVec2(0.0f, 0.0f));
break;
case 2: // right top
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - l_MessagePaddingX, l_MessagePaddingY), ImGuiCond_Always, ImVec2(1.0f, 0));
break;
case 3: // right bottom
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - l_MessagePaddingX, io.DisplaySize.y - l_MessagePaddingY), ImGuiCond_Always, ImVec2(1.0f, 1.0f));
break;
}
ImGui::Begin("Message", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing);
ImGui::Text("%s", l_Message.c_str());
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
void OnScreenDisplayPause(void)
{
l_RenderingPaused = true;
}
void OnScreenDisplayResume(void)
{
l_RenderingPaused = false;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef RMG_ONSCREENDISPLAY_HPP
#define RMG_ONSCREENDISPLAY_HPP
#include <string>
// attempts to initialize the OSD
bool OnScreenDisplayInit(void);
// shuts down the OSD when initialized
void OnScreenDisplayShutdown(void);
// loads settings for the OSD
void OnScreenDisplayLoadSettings(void);
// sets the display size for the OSD
bool OnScreenDisplaySetDisplaySize(int width, int height);
// sets the current message to the OSD
void OnScreenDisplaySetMessage(std::string message);
// renders the OSD
void OnScreenDisplayRender(void);
// pauses OSD rendering
void OnScreenDisplayPause(void);
// resumes OSD rendering
void OnScreenDisplayResume(void);
#endif // RMG_ONSCREENDISPLAY_HPP
+2 -3
View File
@@ -44,9 +44,8 @@ class EmulationThread : public QThread
void on_VidExt_ResizeWindow(int, int);
void on_VidExt_Init(void);
void on_VidExt_SetMode(int, int, int, int, int);
void on_VidExt_SetWindowedModeWithRate(int, int, int, int, int);
void on_VidExt_SetFullscreenModeWithRate(int, int, int, int, int);
void on_VidExt_SetWindowedMode(int, int, int, int);
void on_VidExt_SetFullscreenMode(int, int, int, int);
void on_VidExt_SetCaption(QString);
void on_VidExt_ToggleFS(bool);
void on_VidExt_Quit(void);
+34 -15
View File
@@ -12,11 +12,13 @@
#include <QDir>
#include <QDirIterator>
#include <QElapsedTimer>
using namespace Thread;
RomSearcherThread::RomSearcherThread(QObject *parent) : QThread(parent)
{
qRegisterMetaType<CoreRomType>("CoreRomType");
qRegisterMetaType<CoreRomHeader>("CoreRomHeader");
qRegisterMetaType<CoreRomSettings>("CoreRomSettings");
}
@@ -28,22 +30,22 @@ RomSearcherThread::~RomSearcherThread(void)
void RomSearcherThread::SetDirectory(QString directory)
{
this->rom_Directory = directory;
this->directory = directory;
}
void RomSearcherThread::SetRecursive(bool value)
{
this->rom_Search_Recursive = value;
this->recursive = value;
}
void RomSearcherThread::SetMaximumFiles(int value)
{
this->rom_Search_MaxItems = value;
this->maxItems = value;
}
void RomSearcherThread::Stop(void)
{
this->rom_Search_Stop = true;
this->stop = true;
while (this->isRunning())
{
this->wait();
@@ -52,12 +54,12 @@ void RomSearcherThread::Stop(void)
void RomSearcherThread::run(void)
{
this->rom_Search_Stop = false;
this->rom_Search(this->rom_Directory);
this->stop = false;
this->searchDirectory(this->directory);
return;
}
void RomSearcherThread::rom_Search(QString directory)
void RomSearcherThread::searchDirectory(QString directory)
{
QDir dir(directory);
@@ -69,11 +71,12 @@ void RomSearcherThread::rom_Search(QString directory)
filter << "*.D64";
filter << "*.ZIP";
QDirIterator::IteratorFlag flag = this->rom_Search_Recursive ?
QDirIterator::IteratorFlag flag = this->recursive ?
QDirIterator::Subdirectories :
QDirIterator::NoIteratorFlags;
QDirIterator romDirIt(directory, filter, QDir::Files, flag);
CoreRomType type;
CoreRomHeader header;
CoreRomSettings settings;
bool ret;
@@ -83,39 +86,55 @@ void RomSearcherThread::rom_Search(QString directory)
{
QString file = romDirIt.next();
QElapsedTimer timer;
timer.start();
if (CoreHasRomHeaderAndSettingsCached(file.toStdU32String()))
{ // found cache entry
ret = CoreGetCachedRomHeaderAndSettings(file.toStdU32String(), header, settings);
ret = CoreGetCachedRomHeaderAndSettings(file.toStdU32String(), type, header, settings);
}
else
{ // no cache entry
// open rom, retrieve rom settings & header
ret = CoreOpenRom(file.toStdU32String()) &&
ret = CoreOpenRom(file.toStdU32String()) &&
CoreGetCurrentRomSettings(settings) &&
CoreGetCurrentRomHeader(header);
if (ret)
{
type = CoreGetRomType();
}
// always close the ROM,
// even when retrieving rom info failed
ret = CoreCloseRom() && ret;
if (ret)
{ // add to cache when everything succeeded
CoreAddCachedRomHeaderAndSettings(file.toStdU32String(), header, settings);
CoreAddCachedRomHeaderAndSettings(file.toStdU32String(), type, header, settings);
}
}
if (ret)
{
if (count++ >= this->rom_Search_MaxItems)
if (count++ >= this->maxItems)
{
return;
break;
}
emit this->on_Rom_Found(file, header, settings);
emit this->RomFound(file, type, header, settings);
}
if (this->rom_Search_Stop)
if (this->stop)
{
break;
}
// ensure the UI thread has some breathing room
// instead of being locked up and unable to render anything
if (timer.elapsed() < 10)
{
QThread::msleep(10 - timer.elapsed());
}
}
emit this->Finished(this->stop);
}
+7 -6
View File
@@ -33,15 +33,16 @@ class RomSearcherThread : public QThread
void run(void) override;
private:
QString rom_Directory;
bool rom_Search_Recursive;
int rom_Search_MaxItems;
bool rom_Search_Stop = false;
QString directory;
bool recursive = false;
int maxItems = 0;
bool stop = false;
void rom_Search(QString);
void searchDirectory(QString);
signals:
void on_Rom_Found(QString file, CoreRomHeader header, CoreRomSettings settings);
void RomFound(QString file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
void Finished(bool canceled);
};
} // namespace Thread
@@ -9,13 +9,13 @@
*/
#include "AboutDialog.hpp"
#include "Config.hpp"
#include <RMG-Core/Core.hpp>
using namespace UserInterface::Dialog;
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
{
this->setupUi(this);
this->versionLabel->setText(QString("RMG %1").arg(VERSION_STR));
this->versionLabel->setText(QString("RMG %1").arg(QString::fromStdString(CoreGetVersion())));
}
@@ -94,7 +94,7 @@
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Copyright © 2020-2022 Rosalie Wanders</string>
<string>Copyright © 2020-2023 Rosalie Wanders</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -22,7 +22,7 @@
using namespace UserInterface::Dialog;
AddCheatDialog::AddCheatDialog(QWidget *parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
AddCheatDialog::AddCheatDialog(QWidget *parent) : QDialog(parent)
{
this->setupUi(this);

Some files were not shown because too many files have changed in this diff Show More