Compare commits

...

360 Commits

Author SHA1 Message Date
Rosalie Wanders bfbbbdda7b 3rdParty: update mupen64plus-input-gcn 2023-05-06 00:03:19 +02:00
Rosalie Wanders 67a885b43b 3rdParty: update mupen64plus-input-gcn 2023-05-05 23:26:50 +02:00
Rosalie Wanders a49fe03fc2 3rdParty: update mupen64plus-input-gcn 2023-05-05 22:21:29 +02:00
Rosalie Wanders a7b07dc0f9 ci: install libusb 2023-05-05 22:02:50 +02:00
Rosalie Wanders f9a767f8ae 3rdParty: remove mupen64plus-input-gca and add mupen64plus-input-gcn 2023-05-05 21:57:47 +02:00
Rosalie Wanders 42a4786a25 cmake: remove NO_RUST option 2023-05-05 21:57:29 +02:00
Rosalie Wanders b166eac200 Package: update InGame.png 2023-05-04 23:29:12 +02:00
Rosalie Wanders c06316f4aa Package: update RomBrowser.png 2023-05-04 23:27:22 +02:00
Rosalie Wanders 09d96d9e4d README: improve Support section 2023-05-04 23:18:23 +02:00
Rosalie Wanders 66703970b6 Package: v0.4.0 2023-05-04 22:49:45 +02:00
Rosalie Wanders 0d3314a39b 3rdParty: update mupen64plus-input-gca 2023-05-04 22:41:22 +02:00
Rosalie Wanders 748492cc68 Data: add more custom cheats from Gent 2023-05-04 22:25:00 +02:00
Rosalie Wanders e18ad31c53 RMG: set default QSurfaceFormat with vsync disabled in main.cpp 2023-05-04 22:24:32 +02:00
Rosalie Wanders 0dd297f0f8 3rdParty: update angrylion-rdp-plus 2023-04-24 16:42:52 +02:00
Rosalie Wanders 0da4becd46 3rdParty: update parallel-rsp 2023-04-24 16:40:35 +02:00
Rosalie Wanders d284911d4a Installer: don't skip Run when silent 2023-04-16 00:12:11 +02:00
Rosalie Wanders e772eb3906 RMG: don't install desktop icon on update on windows 2023-04-16 00:11:48 +02:00
Rosalie Wanders 577ee4c3e0 3rdParty: update GLideN64 2023-04-15 16:00:58 +02:00
Rosalie Wanders c534df8303 RMG: disable floating on toolbar 2023-04-13 17:47:47 +02:00
Rosalie Wanders a36c8f7de8 3rdParty: update SDL_GameControllerDB 2023-04-07 22:42:11 +02:00
Rosalie Wanders dfb5f1b687 Package: update InputSettings.png 2023-04-07 21:58:29 +02:00
Rosalie Wanders d8eea015fd RMG: allow the toolbar to be moved 2023-04-07 20:54:20 +02:00
Rosalie Wanders f17b7eb2c9 RMG-Core: add GUI_ToolbarArea setting 2023-04-07 20:52:06 +02:00
Rosalie Wanders 33146626a9 Package: v0.3.9 2023-04-06 14:34:29 +02:00
Rosalie Wanders 78e12f774d RMG: add "Edit Game Input Settings" to the context menu of the ROM browser 2023-04-06 14:11:58 +02:00
Rosalie Wanders 689d8debb1 RMG-Input: implement PluginConfig2() and PluginConfig2HasRomConfig() 2023-04-06 14:11:20 +02:00
Rosalie Wanders 8be1ed8af5 RMG-Core: introduce CorePluginsHasROMConfig() and CorePluginsOpenROMConfig() 2023-04-06 14:09:34 +02:00
Rosalie Wanders 0fabdb3f3a RMG-Input: account for versions which didn't have the sensitivity setting in main.cpp 2023-04-06 08:56:49 +02:00
Rosalie Wanders 7a64e7e479 RMG: show progress status in the loading screen of the ROM browser 2023-04-06 01:20:48 +02:00
Rosalie Wanders 8c1589d7cd RMG-Core: correct error message in read_7zip_file 2023-04-06 00:37:31 +02:00
Rosalie Wanders 5a74b137f2 RMG: implement 7-Zip support 2023-04-06 00:28:31 +02:00
Rosalie Wanders 52ba182610 RMG-Core: implement 7-Zip support 2023-04-06 00:28:31 +02:00
Rosalie Wanders b07eb79609 3rdParty: add 7-Zip 2023-04-06 00:28:31 +02:00
Rosalie Wanders 4e3915f527 RMG: only show 'Don't check for updates again' checkbox when needed 2023-04-05 16:22:27 +02:00
Rosalie Wanders 9f620f276d RMG-Input: account for versions which didn't have the sensitivity setting 2023-04-05 16:18:56 +02:00
JaxonWasTaken e3787b5ccf RMG-Input: implement "Analog Stick Sensitivity" 2023-03-31 19:47:31 +02:00
Rosalie Wanders 3d81a052c6 cmake: add NO_RUST option 2023-03-25 20:34:37 +01:00
Rosalie Wanders 6353be1599 RMG: expose CoreOverlay_SaveFileNameFormat setting 2023-03-12 21:47:20 +01:00
Rosalie Wanders bc6ee4877b RMG-Core: use {Core,CoreOverlay}_SaveFileNameFormat settings 2023-03-12 21:47:20 +01:00
Rosalie Wanders 6b38cc3740 RMG-Core: introduce {Core,CoreOverlay}_SaveFileNameFormat settings 2023-03-12 21:47:20 +01:00
Rosalie Wanders 9285fb9fdf 3rdParty: update mupen64plus-core 2023-03-12 21:47:19 +01:00
Rosalie Wanders f5c609413a Package: update archlinux PKGBUILD 2023-03-04 23:33:08 +01:00
RetraCarteR a304f11b1d RMG: introduce more columns (#119) 2023-03-04 23:10:01 +01:00
Rosalie Wanders e10ac1086f RMG: show window after opening ROM 2023-02-25 14:45:28 +01:00
Rosalie Wanders 4533ed61ac 3rdParty: update GLideN64 2023-02-25 14:44:15 +01:00
Rosalie Wanders 235e41653d Package: v0.3.8 2023-02-24 22:51:20 +01:00
Rosalie Wanders 433479b1c3 RMG: add date and time to OSD when selecting a save state slot 2023-02-24 22:47:29 +01:00
Rosalie Wanders 2b4736f224 RMG: add actions in MainWindow::Init() when showUI is false 2023-02-24 22:30:01 +01:00
Rosalie Wanders 41f1dcf9d2 RMG: use RomBrowser_ColumnVisibility 2023-02-24 22:19:41 +01:00
Rosalie Wanders 45b97cf39b RMG-Core: rename RomBrowser_Columns to RomBrowser_ColumnVisibility 2023-02-24 22:19:27 +01:00
Rosalie Wanders 95b1225219 3rdParty: update GLideN64 2023-02-24 22:08:43 +01:00
Rosalie Wanders 70f6c40b26 RMG: use Keybinding_ViewLog setting 2023-02-24 21:48:28 +01:00
Rosalie Wanders 43bc54fca9 RMG-Core: add Keybinding_ViewLog setting 2023-02-24 21:48:12 +01:00
Rosalie Wanders a5ec31ffef RMG: hook up state callback 2023-02-24 21:37:24 +01:00
Rosalie Wanders 81cbf82ddc RMG-Core: implement state callback 2023-02-24 21:36:54 +01:00
Rosalie Wanders 6cea506c6f RMG: implement -d/--debug-messages commandline option 2023-02-24 21:14:48 +01:00
Rosalie Wanders d7d49f261d RMG-Core: introduce CoreSetPrintDebugCallback() 2023-02-24 21:14:27 +01:00
Rosalie Wanders 4692a5c0b7 RMG-Core: use string() for std::filesystem::path in CoreGetSaveStatePath() 2023-02-24 20:04:43 +01:00
Rosalie Wanders d32ea32f1e Package: slight corrections to appdata 2023-02-24 19:57:27 +01:00
Rosalie Wanders f5f053cc4e RMG: add date and time to save state slot items in "Current Save State" 2023-02-24 19:54:24 +01:00
Rosalie Wanders bb3c6dc9fc RMG-Core: introduce CoreGetSaveStatePath() 2023-02-24 19:52:13 +01:00
RetraCarteR 496d4de1de RMG: slightly refactor RomBrowserWidget.cpp (#113) 2023-02-24 18:50:18 +01:00
Rosalie Wanders 71f8437ecb RMG: fix crash in RomBrowserWidget::on_RomBrowserThread_Finished() 2023-02-24 18:40:54 +01:00
Rosalie Wanders e7767105d6 RMG: simplify sanitizing filename in RomBrowserWidget 2023-02-24 00:46:07 +01:00
RetraCarteR 9cfda8514e RMG: implement toggling visibility for columns (#111) 2023-02-24 00:13:51 +01:00
Rosalie Wanders e0c6700a4d RMG: add info about LLE plugins to settings dialog 2023-02-23 22:10:57 +01:00
Rosalie Wanders 12bf158398 RMG: slightly refactor MainWindow.{cpp,hpp} 2023-02-23 21:38:21 +01:00
Rosalie Wanders ea01c86821 RMG: check for updates once an hour and add 'Check For Updates' to View 2023-02-23 15:45:32 +01:00
Rosalie Wanders 96459432a6 RMG-Core: add GUI_LastUpdateCheck setting 2023-02-23 15:36:15 +01:00
Rosalie Wanders 089194c663 Package: add version to AppImage filename 2023-02-23 14:54:28 +01:00
Rosalie Wanders 7a70227535 RMG: handle SIGINT and SIGTERM 2023-02-23 14:42:59 +01:00
Rosalie Wanders 7adfb3123b RMG: use new settings hotkeys 2023-02-23 14:31:19 +01:00
Rosalie Wanders 1d28075601 RMG-Input: add more settings hotkeys 2023-02-23 14:30:43 +01:00
Rosalie Wanders af7aa688bb RMG: implement -n/--nogui commandline option 2023-02-23 14:08:24 +01:00
Rosalie Wanders beb524f523 RMG: keep trying to set video size until it succeeds 2023-02-23 13:57:21 +01:00
Rosalie 18c9c151a8 RMG: hide AppImage commandline options 2023-02-23 09:07:00 +01:00
Rosalie Wanders 83820baf79 Package: v0.3.7 2023-02-19 22:42:49 +01:00
Rosalie Wanders abf50350e7 RMG: account for full path in plugin settings 2023-02-19 22:40:17 +01:00
Rosalie Wanders 6588d0d17a RMG: account for invalid GUI_IconTheme setting value 2023-02-19 22:35:31 +01:00
Rosalie Wanders 648736df48 Package: correct PKGBUILD 2023-02-19 19:22:29 +01:00
Rosalie Wanders 6278a443df ci: add appstream to ubuntu packages 2023-02-19 19:21:45 +01:00
Rosalie Wanders 615295f1f9 Package: v0.3.6 2023-02-19 13:20:57 +01:00
Rosalie Wanders 593135d02b gitignore: add AppImage things 2023-02-19 12:57:42 +01:00
Rosalie Wanders 78ea41a2ca RMG: always go back to ROM Browser when the plugins aren't ready 2023-02-19 12:56:54 +01:00
Rosalie Wanders 105600878e cmake: only allow AppImage updater on linux 2023-02-19 12:33:19 +01:00
Rosalie Wanders 415202e15f RMG: set original file permissions to updated AppImage 2023-02-19 12:28:36 +01:00
Rosalie Wanders 618a6f6c9f Package: change ArchLinux PKGBUILD to use the latest version 2023-02-19 01:01:24 +01:00
Rosalie Wanders af70f35bf2 README: add Download section 2023-02-19 01:01:24 +01:00
Rosalie Wanders 43bb0a3a1c ci: add -DUPDATER=ON -DAPPIMAGE_UPDATER=ON to AppImage build 2023-02-19 01:01:24 +01:00
Rosalie Wanders 8d9f83b1cc RMG: implement AppImage updater 2023-02-19 01:01:24 +01:00
Rosalie Wanders 7d713afbdd cmake: add APPIMAGE_UPDATER option 2023-02-19 01:01:24 +01:00
Rosalie Wanders 5044ef8ab1 Package: specify OUTPUT in AppImage Create.sh 2023-02-19 01:01:24 +01:00
Rosalie 5b4fe5667a ci: use ubuntu 20.04 LTS and add qt6 backport PPA 2023-02-19 01:01:24 +01:00
Rosalie Wanders a4d3efa087 RMG-Core: use filenames instead of absolute paths for plugins 2023-02-19 01:01:24 +01:00
Rosalie Wanders 9cb8adce55 Package: add AppImage files 2023-02-19 01:01:24 +01:00
Rosalie Wanders c061981de0 ci: build AppImage 2023-02-19 01:01:24 +01:00
Rosalie Wanders b2f76fc436 RMG: allow overriding RMG-Core paths using commandline 2023-02-19 01:01:22 +01:00
Rosalie Wanders dc58fbe900 RMG-Core: add CoreSet*PathOverride functions 2023-02-18 00:46:22 +01:00
Rosalie Wanders 0e80142da1 Package: remove empty description tag from appdata.xml 2023-02-18 00:35:30 +01:00
Rosalie Wanders ee77bc7c9b RMG: use the additional SpeedFactor settings 2023-02-17 22:03:25 +01:00
Rosalie Wanders b978248c03 RMG-Core: add more SpeedFactor settings 2023-02-17 22:02:50 +01:00
Rosalie Wanders 85d2b5be5a RMG: skip non-fatal mupen64plus errors 2023-02-17 21:48:11 +01:00
Rosalie Wanders cee35297d6 cmake: fix default for FORCE_XCB option 2023-02-17 21:38:10 +01:00
Rosalie Wanders edde08849f cmake: add FORCE_XCB option 2023-02-17 21:21:24 +01:00
RetraCarteR f649053e00 Add Ability to Move and Re-order Columns in "Game List" Mode (#105) 2023-02-17 10:45:14 +01:00
Rosalie Wanders 6c6b4bcd3a RMG: add Speed Factor hotkeys to {add,remove}FullscreenActions() 2023-02-16 19:37:40 +01:00
Rosalie Wanders 1fef816572 RMG: move changing speed factor to it's own function & add OSD message 2023-02-14 23:00:55 +01:00
Rosalie Wanders a6203cf6e9 RMG: add speed factor keybindings 2023-02-14 22:53:17 +01:00
Rosalie Wanders 200bb0f6e3 RMG-Core: add speed factor keybinding settings 2023-02-14 22:53:17 +01:00
Rosalie Wanders 1dd2fca3db RMG: add "Speed Factor" to System menubar 2023-02-14 22:37:20 +01:00
Rosalie Wanders 5444f3b807 RMG-Core: introduce SpeedFactor functions 2023-02-14 22:36:15 +01:00
Rosalie Wanders 897d81a188 RMG: add support for stylesheets & GUI_IconTheme setting 2023-02-14 21:12:34 +01:00
Rosalie Wanders eae18c446a RMG-Core: add GUI_IconTheme setting 2023-02-14 21:11:56 +01:00
Rosalie Wanders fb7402e394 Package: v0.3.5 2023-02-14 14:29:33 +01:00
Rosalie Wanders 63dc9cbe7c 3rdParty: update mupen64plus-video-parallel 2023-02-14 14:09:07 +01:00
Rosalie Wanders ac63f4809f RMG-Input: fix for loop in MainDialog::accept() 2023-02-14 13:44:55 +01:00
Rosalie Wanders 0bdf3ada25 RMG-Input: correct old profile detection 2023-02-14 13:30:08 +01:00
Rosalie Wanders aa684b903b 3rdParty: update GLideN64 2023-02-14 12:30:04 +01:00
Rosalie Wanders db0ae36702 3rdParty: update mupen64plus-video-parallel 2023-02-13 20:08:00 +01:00
Rosalie Wanders 3d5e812c6f 3rdParty: update mupen64plus-video-parallel 2023-02-13 19:51:51 +01:00
Rosalie Wanders 07f6810835 3rdParty: update mupen64plus-video-parallel 2023-02-13 19:39:02 +01:00
Rosalie Wanders b3e2a43cf8 RMG: use different signature of CoreGetRomType() 2023-02-12 22:35:06 +01:00
Rosalie Wanders 96f4abbc07 RMG-Core: change signature of CoreGetRomType() 2023-02-12 22:34:48 +01:00
Rosalie Wanders d96746c933 RMG: refactor EmulationThread & move license header in RomSearcherThread 2023-02-12 22:24:34 +01:00
Rosalie Wanders 4391ebd94a RMG-Input: fix RevertSettings not deleting profile sections in some cases 2023-02-12 21:54:20 +01:00
Rosalie Wanders 081029e3d1 RMG-Input: fix reset button not working 2023-02-12 21:48:14 +01:00
Rosalie Wanders 541724b63c Package: v0.3.4 2023-02-11 19:48:49 +01:00
Rosalie Wanders 304afbb50d RMG-Input: add Input_FilterEventsFor{Buttons,Axis} settings 2023-02-11 19:47:12 +01:00
Rosalie Wanders 1ba88f48bb RMG-Core: add Input_FilterEventsFor{Buttons,Axis} settings 2023-02-11 19:46:00 +01:00
Rosalie Wanders 8f8c9c35f1 3rdParty: update GLideN64 2023-02-11 15:28:54 +01:00
Rosalie Wanders 1c07d032ef RMG-Input: account for added profiles in RevertSettings() 2023-02-11 15:18:44 +01:00
Rosalie Wanders c500a17b1a RMG-Input: implement reverting settings & improve saving 2023-02-11 14:33:30 +01:00
Rosalie Wanders 6d0347b48a RMG-Core: introduce CoreSettingsRevertSection() 2023-02-11 14:32:43 +01:00
Rosalie Wanders 83af0ff4af RMG-Input: improve per game profile handling 2023-02-11 13:41:26 +01:00
Rosalie Wanders 32c13eee1d RMG-Core: add Input_UseGameProfile setting 2023-02-11 13:40:50 +01:00
Rosalie Wanders 42597a76f0 RMG-Input: handle automatic input device in CheckInputDeviceSettings() 2023-02-11 13:09:32 +01:00
Rosalie Wanders 7c59a520aa RMG: improve updater script for windows 2023-02-10 21:23:25 +01:00
Rosalie Wanders 3c124d8519 RMG-Input: change size policy for top UI elements 2023-02-10 15:01:31 +01:00
Rosalie Wanders 76282a11da RMG-Input: use const wherever possible in main.cpp 2023-02-10 14:35:51 +01:00
Rosalie Wanders 5249bf6a56 RMG-Input: fix button mapping when having multiple mappings in get_axis_state() 2023-02-10 14:23:32 +01:00
Rosalie Wanders 12e0dac777 RMG-Input: store & use initial size in MappingButton 2023-02-10 13:45:31 +01:00
Rosalie Wanders b4e3bede3b Package: v0.3.3 2023-02-09 22:04:00 +01:00
Rosalie Wanders 679731f004 Screenshots: update InputSettings.png 2023-02-09 22:04:00 +01:00
Rosalie Wanders 3bbd29916b RMG-Input: implement creation of profiles 2023-02-09 21:55:45 +01:00
Rosalie Wanders 6516330289 RMG-Input: slight UI changes 2023-02-09 21:53:47 +01:00
Rosalie Wanders 0628ea920b RMG-Input: introduce 'Automatic' input device 2023-02-09 21:53:47 +01:00
Rosalie Wanders 40a4133565 RMG-Core: add Input_{Profiles,UseProfile} setting 2023-02-09 21:53:47 +01:00
Rosalie Wanders b4425fe1be 3rdParty: update mupen64plus-rsp-parallel 2023-02-09 19:24:24 +01:00
Rosalie Wanders 809cbcbc21 3rdParty: update mupen64plus-core 2023-02-09 19:24:04 +01:00
Rosalie Wanders 2ae2b994a8 Package: update Cheats screenshot aswell 2023-02-07 00:44:00 +01:00
Rosalie Wanders 8ce36cdc03 Package: update screenshots 2023-02-06 22:32:30 +01:00
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
Rosalie 7fcc468353 Script: update openssl libs in BundleDependencies.sh 2023-01-18 23:47:35 +01:00
porcino 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
Rosalie 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
206 changed files with 11962 additions and 3653 deletions
+29 -10
View File
@@ -4,27 +4,43 @@ on: [push, pull_request]
jobs:
Linux:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
steps:
- 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 purge grub\* --yes --allow-remove-essential
sudo add-apt-repository ppa:okirby/qt6-backports --yes
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 libusb-1.0-0-dev 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 appstream
- name: Prepare Environment
run: |
echo "GIT_REVISION=$(git describe --tags --always)" >> $GITHUB_ENV
- name: Build RMG (Portable)
run: ./Source/Script/Build.sh Release
- name: Build RMG (AppImage)
run: |
mkdir Build Build/AppImage Bin/ -p
export src_dir="$(pwd)"
export build_dir="$(pwd)/build"
export bin_dir="$(pwd)/Bin/AppImage"
cmake -S "$src_dir" -B "$build_dir" -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -DUPDATER=ON -DAPPIMAGE_UPDATER=ON -DCMAKE_INSTALL_PREFIX="/usr" -G "Ninja"
cmake --build "$build_dir"
cmake --install "$build_dir" --prefix="$bin_dir/usr"
shell: bash
- name: Upload RMG (Portable)
- name: Create AppImage
run: |
./Package/AppImage/Create.sh
shell: bash
- name: Upload RMG (AppImage)
uses: actions/upload-artifact@v3
with:
name: RMG-Portable-Linux64-${{ env.GIT_REVISION }}
path: Bin/Release/*
path: Bin/*.AppImage
Windows:
runs-on: windows-2019
@@ -32,6 +48,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 +58,20 @@ 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-libusb
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: |
+11 -3
View File
@@ -1,7 +1,15 @@
# 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
# AppImage
squashfs-root
*.AppImage
+36 -5
View File
@@ -6,7 +6,10 @@ 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(APPIMAGE_UPDATER "Enables AppImage updater" OFF)
option(DISCORD_RPC "Enables Discord Rich Presence" ON)
option(USE_CCACHE "Enables usage of ccache when ccache has been found" ON)
option(FORCE_XCB "Forces Qt to use the xcb platform on linux" ${LINUX})
project(RMG)
@@ -19,16 +22,40 @@ 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)
if (NOT PORTABLE_INSTALL AND UPDATER AND NOT APPIMAGE_UPDATER)
message(WARNING "Not-Portable builds don't support the updater, disabling UPDATER")
set(UPDATER OFF)
endif()
if (APPIMAGE_UPDATER AND (WIN32 OR MSYS))
message(WARNING "AppImage updater not supported on windows, disabling APPIMAGE_UPDATER!")
set(APPIMAGE_UPDATER OFF)
endif()
if (UPDATER AND NOT (WIN32 OR MSYS) AND NOT APPIMAGE_UPDATER)
message(WARNING "Only AppImage updater is supported on linux, disabling UPDATER!")
set(UPDATER OFF)
endif()
if (FORCE_XCB AND (WIN32 OR MSYS))
message(WARNING "XCB Qt platform not supported on windows, disabling FORCE_XCB!")
set(FORCE_XCB OFF)
endif()
if (PORTABLE_INSTALL)
set(CMAKE_INSTALL_PREFIX "")
set(INSTALL_PATH "Bin/${CMAKE_BUILD_TYPE}")
@@ -49,6 +76,7 @@ else()
endif()
add_subdirectory(Source/3rdParty)
add_subdirectory(Source/3rdParty/7-Zip)
add_subdirectory(Source/RMG-Core)
add_subdirectory(Source/RMG)
@@ -68,14 +96,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)
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)
@@ -95,7 +126,7 @@ install(FILES ${MUPEN64PLUS_PLUGIN_RSP_PARALLEL}
install(FILES ${MUPEN64PLUS_PLUGIN_INPUT_RAPHNET}
DESTINATION ${PLUGIN_INSTALL_PATH}/Input
)
install(FILES ${MUPEN64PLUS_PLUGIN_INPUT_GCA}
install(FILES ${MUPEN64PLUS_PLUGIN_INPUT_GCN}
DESTINATION ${PLUGIN_INSTALL_PATH}/Input
)
install(FILES ${MUPEN64PLUS_PLUGIN_GFX_ANGRYLION}
@@ -0,0 +1,64 @@
[1FBAF161-2C1C54F1-C:41]
Name=1080 Snowboarding (JU) (M2)
$Enable All Levels & Boarders
80255089 00FF
8025508B 0005
81255096 FCFF
80255098 0007
$Have All\Contest First Place Done
80244098 0007
$Have All\Match Levels Completed
8025508A 0005
$Have All\Trick Attacks Done
81255096 FCFF
$Infinite Damage All Players & Levels
803F4C3C 0024
807F4C3C 0024
$Infinite Lives & Continues
8026B1CB 0003
$Always First Place (Player 1)
81267B88 2400
Note=The game will still show you in 2nd when you are behind. But when you cross the finish line, you will win!
$Open Level Character Select
Note=With these codes, you have to press the buttons listed below when you are viewing a certain boarders stats. Highlight Akari Hayami's stats, and then hold down the C-Left button and then press the A button to be the Crystal Boarder. Highlight Kensuke Kimachi's stats, and then hold down the C-Up button and then press the A button to be the Metal Boarder. Hightlight Rob Haywood's stats, and then hold down the C-Right button and then press the A button to be the Panda Boarder
8125508A 00??
01 Easy Level
02 Easy & Normal Level
03 Easy Normal & Hard Levels
04 Easy Normal Hard Levels & Crystal Boarder
05 Easy Normal Hard Levels & Crystal & Metal Boarders
$Play As
800200E7 00??
00 Dion Blaster
01 Kensuke Kimachi
02 Akari Hayami
03 Ricky Winterborn
04 Rob Haywood
05 Silver Boarder
06 Gold Boarder
07 Panda Boarder
$Freeze Timer In\Match Race
D1267B20 05E1
81267B20 1000
$Freeze Timer In\Time Attack
D12660CC 05E1
812660CC 1000
$Freeze Timer In\Trick Attack
D1266138 05E1
81266138 1000
$Freeze Timer In\Contest
D126628C 05E1
8126628C 1000
@@ -0,0 +1,55 @@
[58FD3F25-D92EAA8D-C:50]
Name=1080 Snowboarding (E) (M4)
$Enable All Levels & Boarders
80250AB9 00FF
80250ABB 0005
81250AC6 FCFF
80250AC8 0007
$Infinite Damage All Players and Levels
803F4C00 0024
807F4C00 0024
$Infinite Lives & Continues
802648A4 0003
$Open Level Character Select
Note=With these codes, you have to press the buttons listed below when you are viewing a certain boarders stats. Highlight Akari Hayami's stats, and then hold down the C-Left button and then press the A button to be the Crystal Boarder. Highlight Kensuke Kimachi's stats, and then hold down the C-Up button and then press the A button to be the Metal Boarder. Hightlight Rob Haywood's stats, and then hold down the C-Right button and then press the A button to be the Panda Boarder
8125508A 00??
01 Easy Level
02 Easy & Normal Level
03 Easy Normal & Hard Levels
04 Easy Normal Hard Levels & Crystal Boarder
05 Easy Normal Hard Levels & Crystal & Metal Boarders
$Play As
8001A0E7 00??
00 Dion Blaster
01 Kensuke Kimachi
02 Akari Hayami
03 Ricky Winterborn
04 Rob Haywood
05 Silver Boarder
06 Gold Boarder
07 Panda Boarder
$Always First Place (Player 1)
812679BC 2400
Note=The game will still show you in 2nd when you are behind. But when you cross the finish line, you will win!
$Freeze Timer In\Match Race
D1267954 05E1
81267954 1000
$Freeze Timer In\Time Attack
D1265D4C 05E1
81265D4C 1000
$Freeze Timer In\Trick Attack
D1265DB8 05E1
81265DB8 1000
$Freeze Timer In\Contest
D1265F48 05E1
81265F48 1000
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e
cur_dir="$(readlink -f "$(dirname "$0")")"
exec "$cur_dir/usr/bin/RMG" \
--core-path="$cur_dir/usr/lib/RMG/Core" \
--plugin-path="$cur_dir/usr/lib/RMG/Plugin" \
--shared-data-path="$cur_dir/usr/share/RMG" \
"$@"
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -ex
script_dir="$(dirname "$0")"
toplvl_dir="$(realpath "$script_dir/../../")"
bin_dir="$toplvl_dir/Bin/AppImage" # RMG should be installed here
export QMAKE="$(which qmake6)"
export EXTRA_QT_PLUGINS="imageformats;iconengines;"
export VERSION="$(git describe --tags --always)"
export OUTPUT="$bin_dir/../RMG-Portable-Linux64-$VERSION.AppImage"
if [ ! -f "$script_dir/linuxdeploy-x86_64.AppImage" ]
then
curl -L https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \
-o "$script_dir/linuxdeploy-x86_64.AppImage"
chmod +x "$script_dir/linuxdeploy-x86_64.AppImage"
fi
if [ ! -f "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage" ]
then
curl -L https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage \
-o "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
chmod +x "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
fi
"$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage" --appimage-extract
"$script_dir/linuxdeploy-x86_64.AppImage" --appimage-extract
# delete appimages
rm "$script_dir/linuxdeploy-x86_64.AppImage" \
"$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
"$(pwd)/squashfs-root/AppRun" \
--plugin=qt \
--appdir="$bin_dir" \
--custom-apprun="$script_dir/AppRun" \
--output=appimage \
--desktop-file="$bin_dir/usr/share/applications/com.github.Rosalie241.RMG.desktop"
+14 -29
View File
@@ -1,51 +1,36 @@
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
_pkgname=rmg
pkgname=${_pkgname}-git
pkgver=git
pkgname=rmg
pkgver=0.3.9
pkgrel=1
pkgdesc="Rosalie's Mupen GUI"
arch=('x86_64')
url="https://github.com/Rosalie241/${_pkgname}"
license=('GPLv3')
url="https://github.com/Rosalie241/$pkgname"
license=('GPL3')
provides=("$_pkgname")
conflicts=("$_pkgname")
depends=("hidapi" "libsamplerate" "speexdsp" "minizip" "sdl2" "zlib" "freetype2" "qt6-base" "qt6-svg" "xdg-user-dirs")
makedepends=("git" "nasm" "cmake" "ninja")
depends=("hidapi" "libsamplerate" "minizip" "sdl2" "zlib" "freetype2" "qt5-base" "qt5-svg")
makedepends=("git" "pkg-config" "nasm" "cmake" "rustup")
source=("git+https://github.com/Rosalie241/${_pkgname}.git")
source=("git+https://github.com/Rosalie241/$pkgname.git#tag=v$pkgver")
sha256sums=('SKIP')
pkgver()
{
cd "$_pkgname"
git describe --tags --always | sed -e 's|^v||;s|-|.|g'
}
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" \
cmake -S "$srcdir/$pkgname" -B "$srcdir/$pkgname/build" \
-DCMAKE_BUILD_TYPE="Release" \
-DPORTABLE_INSTALL="OFF" \
-DCMAKE_INSTALL_PREFIX="/usr" \
-G "Unix Makefiles"
make
-DNO_RUST="ON" \
-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: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 57 KiB

+271 -4
View File
@@ -1,4 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<!-- Copyright 2022 Rosalie Wanders -->
<component type="desktop">
<!--Created with jdAppdataEdit 2.1-->
<id>com.github.Rosalie241.RMG</id>
@@ -11,20 +12,286 @@
<description><p>Rosalie's Mupen GUI is an easy to use yet customizable mupen64plus front-end, allowing you to easily play N64 games.</p></description>
<screenshots>
<screenshot type="default">
<caption>The Rom Browser</caption>
<caption>01 - The Rom Browser</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/RomBrowser.png</image>
</screenshot>
<screenshot type="default">
<caption>During A Game</caption>
<caption>02 - During A Game</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InGame.png</image>
</screenshot>
<screenshot type="default">
<caption>Settings</caption>
<caption>03 - Cheats</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Cheats.png</image>
</screenshot>
<screenshot type="default">
<caption>04 - Settings</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Settings.png</image>
</screenshot>
<screenshot type="default">
<caption>05 - 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.4.0" date="2023-05-04" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix updater on windows always installing the desktop icon</li>
<li>Fix updater on windows not re-launching RMG after installation</li>
<li>Fix the speed limiter toggle and speed factor options not working on linux on some systems</li>
<li>Fix the 1080 Snowboarding cheats (thank you Gent)</li>
<li>Add support for moving the toolbar (changes to the docked position are persistent across application runs)</li>
<li>Update GLideN64 and mupen64plus-input-gca</li>
</ul>
</description>
</release>
<release version="v0.3.9" date="2023-04-06" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix "Don't check for updates again" checkbox appearing when requesting an update check through Help -> Check For Updates</li>
<li>Add game format, file name, file extension, file size, game I.D. and game region columns to the list view of the ROM browser which can be toggled in the "Show/Hide Columns" menu of the context menu in the list view of the ROM browser (thank you RetraCarteR)</li>
<li>Add "Reset Column Sizes" to context menu of the list view of the ROM browser (thank you RetraCarteR)</li>
<li>Add "Analog Stick Sensitivity" setting to RMG-Input (thank you JaxonWasTaken)</li>
<li>Add "Save Filename Format" setting to the Core tab of the settings dialog</li>
<li>Add "Edit Game Input Settings" to the context menu of the ROM browser</li>
<li>Add support for 7z files</li>
<li>Add progress status to the loading screen in the ROM browser when loading takes more than 5 seconds</li>
</ul>
</description>
</release>
<release version="v0.3.8" date="2023-02-24" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix RMG not having the correct video size in some cases (i.e on a WM where resizing is not allowed to be done by an application)</li>
<li>Fix translations not working in GLideN64</li>
<li>Add -n/--nogui commandline option</li>
<li>Add -d/--debug-messages commandline option</li>
<li>Add hotkeys for graphics, audio, RSP and input settings</li>
<li>Add hotkey for viewing the log</li>
<li>Add SIGINT and SIGTERM handling on linux</li>
<li>Add "Check For Updates" to "View" in the toolbar</li>
<li>Add information about LLE plugins in the settings dialog</li>
<li>Add support for toggling visibility of columns in the ROM browser list view (thank you RetraCarteR)</li>
<li>Add date and time to the save state slot items in "Current Save State" menu in the menubar</li>
<li>Add date and time to the OSD when selecting a save state slot</li>
<li>Add failure messages to the OSD when loading/saving a save state fails</li>
<li>Improve updater behavior by checking for an update on startup with at least an hour in-between checks</li>
</ul>
</description>
</release>
<release version="v0.3.7" date="2023-02-19" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix icons not showing up in some cases when migrating from a version before v0.3.6</li>
<li>Fix plugin settings not being loaded properly in the settings dialog when migrating from a version before v0.3.6</li>
</ul>
</description>
</release>
<release version="v0.3.6" date="2023-02-19" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix RMG not using xwayland when using wayland (wayland has lots of issues, can be disabled by building with the "-DFORCE_XCB=OFF" option)</li>
<li>Fix some non-fatal mupen64plus errors showing a pop-up</li>
<li>Fix window not returning to ROM browser when launching a game through the commandline and the plugins aren't ready</li>
<li>Add support for Qt stylesheets (place them in the 'user data directory/Styles' directory with the '.qss' extension, they'll show up in "Themes")</li>
<li>Add "Icon Theme" setting</li>
<li>Add "Speed Factor" to System menu bar</li>
<li>Add support for re-ordering columns in the list view of the ROM browser (thank you RetraCarteR)</li>
<li>Add AppImage to github releases (this replaces the old portable linux builds on github releases)</li>
</ul>
</description>
</release>
<release version="v0.3.5" date="2023-02-14" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix reset button not working properly in RMG-Input</li>
<li>Fix profiles not being deleted properly when clicking on cancel/close in some cases in RMG-Input</li>
<li>Fix paraLLEl not logging to the log window</li>
<li>Fix paraLLEl's odd window behavior by not saving the window size when emulation ends</li>
<li>Fix GLideN64 initializing a noise texture being slow</li>
<li>Fix issue where an unbound mapping in RMG-Input would respond to an A controller button press in-game</li>
<li>Fix issue where RMG-Input wouldn't save anything but the currently opened profile</li>
</ul>
</description>
</release>
<release version="v0.3.4" date="2023-02-11" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix mapping button size increasing when reloading settings in RMG-Input</li>
<li>Fix analog stick mapping in-game when having buttons and axis bound in RMG-Input</li>
<li>Fix height mismatch of "Profile" and "Input Device" UI elements in RMG-Input</li>
<li>Fix updater script not using the correct path seperators on Windows</li>
<li>Fix GLideN64's per game settings being overwritten by the updater on windows (or not being updated on linux)</li>
<li>Fix "Automatic" input device not opening controller device when clicking on 'Refresh' in RMG-Input</li>
<li>Fix game specific profile having unexpected UI behavior in RMG-Input</li>
<li>Fix cancel and close button not working correctly in RMG-Input</li>
<li>Fix profile saving not working correctly when having the same profile selected for multiple players in RMG-Input</li>
<li>Add "Filter Events Based On Joystick Type For Buttons" setting to RMG-Input</li>
<li>Add "Filter Events Based On Joystick Type For Axis" setting to RMG-Input</li>
</ul>
</description>
</release>
<release version="v0.3.3" date="2023-02-09" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Remove "Controller Is Plugged In" checkbox in RMG-Input</li>
<li>Remove text from 'Remove' button in RMG-Input</li>
<li>Add "None" input device to RMG-Input (replacing the "Controller Is Plugged In" checkbox)</li>
<li>Add "Automatic" input device to RMG-Input</li>
<li>Add support for creating profiles in RMG-Input</li>
<li>Add icons to 'Remove', 'Refresh', 'Reset' and 'Options' buttons in RMG-Input</li>
</ul>
</description>
</release>
<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>
+39 -28
View File
@@ -4,55 +4,66 @@ 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
## Download
* Operating System
* Windows Or Linux
* CPU
* Intel or AMD processor with SSE2 support
* RAM
* 512MB or more
* Graphics card
* OpenGL 3.3 capable
#### Windows
You can download Rosalie's Mupen GUI on ![Github Releases](https://github.com/Rosalie241/RMG/releases)
#### Linux
You can download Rosalie's Mupen GUI on
* [Github Releases (AppImage)](https://github.com/Rosalie241/RMG/releases)
* [Flathub (Flatpak)](https://flathub.org/apps/details/com.github.Rosalie241.RMG)
* [Arch User Repository](https://aur.archlinux.org/packages/rmg)
## Support
You can ask for help or report issues on
* [Github](https://github.com/Rosalie241/RMG/issues/new)
* [Discord](https://discord.gg/k9GuyJ2PpF)
## 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
```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
```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
```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
```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
```
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -G "Unix Makefiles"
make install
```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/)
```
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
```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`
## Support
Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for support
## 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).
+40
View File
@@ -0,0 +1,40 @@
#
# 7-Zip CMakeLists.txt
#
project(7Zip)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(7ZIP_SOURCES
${CMAKE_CURRENT_BINARY_DIR}/C/Bcj2.c
${CMAKE_CURRENT_BINARY_DIR}/C/Bra.c
${CMAKE_CURRENT_BINARY_DIR}/C/Bra86.c
${CMAKE_CURRENT_BINARY_DIR}/C/BraIA64.c
${CMAKE_CURRENT_BINARY_DIR}/C/CpuArch.c
${CMAKE_CURRENT_BINARY_DIR}/C/Delta.c
${CMAKE_CURRENT_BINARY_DIR}/C/Lzma2Dec.c
${CMAKE_CURRENT_BINARY_DIR}/C/LzmaDec.c
${CMAKE_CURRENT_BINARY_DIR}/C/Ppmd7.c
${CMAKE_CURRENT_BINARY_DIR}/C/Ppmd7Dec.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zCrc.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zCrcOpt.c
${CMAKE_CURRENT_BINARY_DIR}/C/Sha256.c
${CMAKE_CURRENT_BINARY_DIR}/C/Sha256Opt.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zAlloc.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zArcIn.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zBuf.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zBuf2.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zDec.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zFile.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zStream.c
)
add_custom_command(
OUTPUT ${7ZIP_SOURCES}
COMMAND ${CMAKE_COMMAND} -E tar "xvz" "${CMAKE_CURRENT_SOURCE_DIR}/lzma2201.tar.gz"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_definitions(-D_7ZIP_PPMD_SUPPPORT -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE)
add_library(7Zip STATIC ${7ZIP_SOURCES})
+2
View File
@@ -0,0 +1,2 @@
# 7-Zip SDK v22.01
Downloaded from https://www.7-zip.org/sdk.html
Binary file not shown.
+118 -56
View File
@@ -5,55 +5,62 @@ include(ExternalProject)
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 OFF)
else()
set(BUILD_INPUT_GCA ON)
endif()
set(M64P_CORE_DIR ${THIRDPARTY_DIR}/mupen64plus-core)
if(WIN32)
set(SO_EXT "dll")
set(GCA_LIB "mupen64plus_input_gca.${SO_EXT}")
set(CORE_FILE "mupen64plus.dll")
else(WIN32)
set(SO_EXT "so")
set(GCA_LIB "libmupen64plus_input_gca.${SO_EXT}")
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 "ba9a52483052248b67c324e3fd0e073b807bbea4")
set(MUPEN64PLUSCORE_TAG "d4f3e12db0609158c7b4e0beef2bb950aad0ccb9")
set(MUPEN64PLUS_RSP_CXD4_URL "https://github.com/mupen64plus/mupen64plus-rsp-cxd4")
set(MUPEN64PLUS_RSP_CXD4_TAG "39f79201baa15890c4cbae92f2215a634cc3ee6d")
set(MUPEN64PLUS_RSP_HLE_URL "https://github.com/mupen64plus/mupen64plus-rsp-hle")
set(MUPEN64PLUS_RSP_HLE_TAG "88093cb43499eff53d343653cddcae2132af17ef")
set(MUPEN64PLUS_RSP_PARALLEL_URL "https://github.com/Rosalie241/parallel-rsp")
set(MUPEN64PLUS_RSP_PARALLEL_TAG "e67cee3131651c3e48343294d94fa68a6f8ec14c")
set(MUPEN64PLUS_RSP_PARALLEL_TAG "dbecbe3a120e428436c5972fa7b872cfc2c9db3e")
set(MUPEN64PLUS_INPUT_RAPHNET_URL "https://github.com/raphnet/mupen64plus-input-raphnetraw")
set(MUPEN64PLUS_INPUT_RAPHNET_TAG "86112413e98a8648edb11d199673cc24d5799af8")
set(MUPEN64PLUS_INPUT_GCA_URL "https://github.com/amatho/mupen64plus-input-gca")
set(MUPEN64PLUS_INPUT_GCA_TAG "21639fb13dfa797a7c0949ffd9bbda9a3456fc69")
set(MUPEN64PLUS_INPUT_GCN_URL "https://github.com/Rosalie241/mupen64plus-input-gcn")
set(MUPEN64PLUS_INPUT_GCN_TAG "e220115fa8ad223be783c822a251d7e0f873ed4c")
set(MUPEN64PLUS_GFX_ANGRYLION_URL "https://github.com/Rosalie241/angrylion-rdp-plus")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "9d71074f6b71750e99ad06a713f28a9c32ad15cb")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "670abbc972bd430fa77291b0967dd73128314317")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/gonetz/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "ff47414c2bd6e572872e9148b2f3e1dbc83e5fee")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "0fee30d010d1feda7d343654871b3dfd05ccab70")
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "693f607728aca78d94ba5d45b0ce119b4ccbcd8c")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "2c2226517c4c8929e08ec944654867e26efe0cf5")
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 "b7e5701da82fc97beeede64d3818ef0f4d015aba")
endif(NOT NO_GIT_CLONE)
ExternalProject_Add(mupen64plus-core
@@ -65,7 +72,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
@@ -84,7 +91,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
@@ -102,7 +109,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
@@ -120,7 +127,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
@@ -135,7 +142,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
@@ -144,31 +151,29 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
DEPENDS mupen64plus-core
)
if (BUILD_INPUT_GCA)
ExternalProject_Add(mupen64plus-input-gca
SOURCE_DIR mupen64plus-input-gca/
ExternalProject_Add(mupen64plus-input-gcn
SOURCE_DIR mupen64plus-input-gcn
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
GIT_REPOSITORY ${MUPEN64PLUS_INPUT_GCN_URL}
GIT_TAG ${MUPEN64PLUS_INPUT_GCN_TAG}
GIT_REPOSITORY ${MUPEN64PLUS_INPUT_GCA_URL}
GIT_TAG ${MUPEN64PLUS_INPUT_GCA_TAG}
INSTALL_COMMAND ""
BUILD_COMMAND cargo build --release --features "m64p_compat"
BUILD_IN_SOURCE True
BUILD_IN_SOURCE True
CMAKE_ARGS ${CMAKE_CONFIGURE_ARGS}
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-gca/target/release/${GCA_LIB}
DEPENDS mupen64plus-core
)
endif(BUILD_INPUT_GCA)
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-gcn/mupen64plus-input-gcn.${SO_EXT}
DEPENDS mupen64plus-core
)
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})
@@ -184,7 +189,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
@@ -199,14 +204,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
@@ -218,7 +221,7 @@ 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
@@ -234,12 +237,66 @@ if (DISCORD_RPC)
INSTALL_COMMAND ""
BUILD_IN_SOURCE True
CMAKE_ARGS -DBUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_POSITION_INDEPENDENT_CODE=ON
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)
@@ -256,21 +313,26 @@ 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)
ExternalProject_Get_property(mupen64plus-input-gca BUILD_BYPRODUCTS)
set(MUPEN64PLUS_PLUGIN_INPUT_GCA ${BUILD_BYPRODUCTS} PARENT_SCOPE)
endif(BUILD_INPUT_GCA)
ExternalProject_Get_property(mupen64plus-input-gcn BUILD_BYPRODUCTS)
set(MUPEN64PLUS_PLUGIN_INPUT_GCN ${BUILD_BYPRODUCTS} PARENT_SCOPE)
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)
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)
+1 -1
View File
@@ -55,5 +55,5 @@ Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
+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>
+3
View File
@@ -24,6 +24,7 @@ set(RMG_CORE_SOURCES
ConvertStringEncoding.cpp
Settings/Settings.cpp
SpeedLimiter.cpp
SpeedFactor.cpp
RomSettings.cpp
Directories.cpp
MediaLoader.cpp
@@ -33,6 +34,7 @@ set(RMG_CORE_SOURCES
SaveState.cpp
Callback.cpp
Plugins.cpp
Version.cpp
Cheats.cpp
VidExt.cpp
Video.cpp
@@ -78,6 +80,7 @@ endif(WIN32)
target_link_libraries(RMG-Core
${MINIZIP_LIBRARIES}
7Zip
)
if (DISCORD_RPC)
+42 -4
View File
@@ -36,11 +36,13 @@
#define ROMHEADER_NAME_LEN 256
#define GOODNAME_LEN 256
#define MD5_LEN 33
#define GAMEID_LEN 5
#define REGION_LEN 18
#ifdef _WIN32
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheWindows_04"
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheWindows_06"
#else // Linux
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheLinux_04"
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheLinux_06"
#endif // _WIN32
#define CACHE_FILE_ITEMS_MAX 10000
@@ -53,6 +55,7 @@ struct l_CacheEntry
std::filesystem::path fileName;
osal_files_file_time fileTime;
CoreRomType type;
CoreRomHeader header;
CoreRomSettings settings;
};
@@ -102,6 +105,8 @@ void CoreReadRomHeaderAndSettingsCache(void)
char magicBuf[sizeof(CACHE_FILE_MAGIC)];
wchar_t fileNameBuf[MAX_FILENAME_LEN];
char headerNameBuf[ROMHEADER_NAME_LEN];
char gameIDBuf[GAMEID_LEN];
char regionBuf[REGION_LEN];
char goodNameBuf[GOODNAME_LEN];
char md5Buf[MD5_LEN];
uint32_t size;
@@ -130,6 +135,8 @@ void CoreReadRomHeaderAndSettingsCache(void)
size = 0;
memset(fileNameBuf, 0, sizeof(fileNameBuf));
memset(headerNameBuf, 0, sizeof(headerNameBuf));
memset(gameIDBuf, 0, sizeof(gameIDBuf));
memset(regionBuf, 0, sizeof(regionBuf));
memset(goodNameBuf, 0, sizeof(goodNameBuf));
memset(md5Buf, 0, sizeof(md5Buf));
@@ -138,10 +145,18 @@ void CoreReadRomHeaderAndSettingsCache(void)
FREAD_STR(fileNameBuf, size);
cacheEntry.fileName = std::filesystem::path(fileNameBuf);
FREAD(cacheEntry.fileTime);
// type
FREAD(cacheEntry.type);
// header
FREAD(size);
FREAD_STR(headerNameBuf, size);
FREAD(size);
FREAD_STR(gameIDBuf, size);
FREAD(size);
FREAD_STR(regionBuf, size);
cacheEntry.header.Name = std::string(headerNameBuf);
cacheEntry.header.GameID = std::string(gameIDBuf);
cacheEntry.header.Region = std::string(regionBuf);
FREAD(cacheEntry.header.CRC1);
FREAD(cacheEntry.header.CRC2);
// (partial) settings
@@ -166,6 +181,8 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
std::ofstream outputStream;
wchar_t fileNameBuf[MAX_FILENAME_LEN];
char headerNameBuf[ROMHEADER_NAME_LEN];
char gameIDBuf[GAMEID_LEN];
char regionBuf[REGION_LEN];
char goodNameBuf[GOODNAME_LEN];
char md5Buf[MD5_LEN];
uint32_t size;
@@ -197,12 +214,16 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
size = 0;
memset(fileNameBuf, 0, sizeof(fileNameBuf));
memset(headerNameBuf, 0, sizeof(headerNameBuf));
memset(gameIDBuf, 0, sizeof(gameIDBuf));
memset(regionBuf, 0, sizeof(regionBuf));
memset(goodNameBuf, 0, sizeof(goodNameBuf));
memset(md5Buf, 0, sizeof(md5Buf));
// copy strings into buffers
wcsncpy(fileNameBuf, cacheEntry.fileName.wstring().c_str(), MAX_FILENAME_LEN);
strncpy(headerNameBuf, cacheEntry.header.Name.c_str(), sizeof(headerNameBuf));
strncpy(gameIDBuf, cacheEntry.header.GameID.c_str(), sizeof(gameIDBuf));
strncpy(regionBuf, cacheEntry.header.Region.c_str(), sizeof(regionBuf));
strncpy(goodNameBuf, cacheEntry.settings.GoodName.c_str(), sizeof(goodNameBuf));
strncpy(md5Buf, cacheEntry.settings.MD5.c_str(), sizeof(md5Buf));
@@ -211,10 +232,18 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
FWRITE(size);
FWRITE_STR(fileNameBuf, size);
FWRITE(cacheEntry.fileTime);
// type
FWRITE(cacheEntry.type);
// header
size = cacheEntry.header.Name.size();
FWRITE(size);
FWRITE_STR(headerNameBuf, size);
size = cacheEntry.header.GameID.size();
FWRITE(size);
FWRITE_STR(gameIDBuf, size);
size = cacheEntry.header.Region.size();
FWRITE(size);
FWRITE_STR(regionBuf, size);
FWRITE(cacheEntry.header.CRC1);
FWRITE(cacheEntry.header.CRC2);
// (partial) settings
@@ -237,7 +266,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())
@@ -245,12 +274,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;
@@ -268,6 +298,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;
@@ -275,3 +306,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
+26 -4
View File
@@ -11,12 +11,16 @@
#include "Core.hpp"
#include "ConvertStringEncoding.hpp"
#include <iostream>
//
// 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;
static std::function<void(enum CoreStateCallbackType, int)> l_StateCallbackFunc;
static bool l_PrintCallbacks = false;
//
// Internal Functions
@@ -29,6 +33,7 @@ void CoreDebugCallback(void* context, int level, const char* message)
return;
}
std::string contextString((const char*)context);
std::string messageString(message);
// convert string encoding accordingly
@@ -41,21 +46,38 @@ void CoreDebugCallback(void* context, int level, const char* message)
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::Shift_JIS);
}
l_DebugCallbackFunc((CoreDebugMessageType)level, messageString);
if (l_PrintCallbacks)
{
std::cout << contextString << messageString << std::endl;
}
l_DebugCallbackFunc((CoreDebugMessageType)level, contextString, messageString);
}
void CoreStateCallback(void* context, m64p_core_param param, int value)
{
// TODO
if (!l_SetupCallbacks)
{
return;
}
l_StateCallbackFunc((CoreStateCallbackType)param, 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,
std::function<void(enum CoreStateCallbackType, int)> stateCallbackFunc)
{
l_DebugCallbackFunc = debugCallbackFunc;
l_StateCallbackFunc = stateCallbackFunc;
l_SetupCallbacks = true;
return true;
}
void CoreSetPrintDebugCallback(bool enabled)
{
l_PrintCallbacks = enabled;
}
+21 -1
View File
@@ -32,6 +32,26 @@ enum class CoreDebugMessageType
Verbose = 5
};
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string)> debugCallbackFunc);
enum class CoreStateCallbackType
{
EmulationState = 1,
VideoMode,
SaveStateSlot,
SpeedFactor,
SpeedLimiter,
VideoSize,
AudioVolume,
AudioMute,
GamesharkInput,
SaveStateLoaded,
SaveStateSaved,
};
// attempts to setup callbacks with the provided functions
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc,
std::function<void(enum CoreStateCallbackType, int)> stateCallbackFunc);
// sets whether the debug callbacks will be printed to stdout
void CoreSetPrintDebugCallback(bool enabled);
#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
+15 -9
View File
@@ -17,29 +17,32 @@
#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)
@@ -76,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())
{
@@ -89,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: ";
@@ -114,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: ";
+2
View File
@@ -13,6 +13,7 @@
#include "CachedRomHeaderAndSettings.hpp"
#include "Settings/Settings.hpp"
#include "SpeedLimiter.hpp"
#include "SpeedFactor.hpp"
#include "RomSettings.hpp"
#include "Directories.hpp"
#include "MediaLoader.hpp"
@@ -22,6 +23,7 @@
#include "RomHeader.hpp"
#include "Callback.hpp"
#include "Plugins.hpp"
#include "Version.hpp"
#include "Cheats.hpp"
#include "Error.hpp"
#include "Unzip.hpp"
+55 -9
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>
@@ -18,6 +18,14 @@
#include <iostream>
#include <filesystem>
//
// Local Variables
//
static std::filesystem::path l_CorePathOverride;
static std::filesystem::path l_PluginPathOverride;
static std::filesystem::path l_SharedDataPathOverride;
//
// Local Functions
//
@@ -123,8 +131,15 @@ std::filesystem::path CoreGetCoreDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Core";
#else // Not Portable
directory = CORE_INSTAlL_PREFIX;
directory += "/lib/RMG/Core";
if (!l_CorePathOverride.empty())
{
directory = l_CorePathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Core";
}
#endif // PORTABLE_INSTALL
return directory;
}
@@ -135,8 +150,15 @@ std::filesystem::path CoreGetPluginDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Plugin";
#else // Not Portable
directory = CORE_INSTAlL_PREFIX;
directory += "/lib/RMG/Plugin";
if (!l_PluginPathOverride.empty())
{
directory = l_PluginPathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Plugin";
}
#endif // PORTABLE_INSTALL
return directory;
}
@@ -180,7 +202,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 +214,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,8 +255,15 @@ std::filesystem::path CoreGetSharedDataDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Data";
#else // Not Portable
directory = CORE_INSTAlL_PREFIX;
directory += "/share/RMG";
if (!l_SharedDataPathOverride.empty())
{
directory = l_SharedDataPathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/share/RMG";
}
#endif // PORTABLE_INSTALL
return directory;
}
@@ -253,3 +282,20 @@ std::filesystem::path CoreGetScreenshotDirectory(void)
{
return CoreSettingsGetStringValue(SettingsID::Core_ScreenshotPath);
}
#ifndef PORTABLE_INSTALL
void CoreSetCorePathOverride(std::filesystem::path path)
{
l_CorePathOverride = path;
}
void CoreSetPluginPathOverride(std::filesystem::path path)
{
l_PluginPathOverride = path;
}
void CoreSetSharedDataPathOverride(std::filesystem::path path)
{
l_SharedDataPathOverride = path;
}
#endif // PORTABLE_INSTALL
+9
View File
@@ -73,4 +73,13 @@ std::filesystem::path CoreGetSaveStateDirectory(void);
// screenshots should be located
std::filesystem::path CoreGetScreenshotDirectory(void);
// changes the core path to the given path
void CoreSetCorePathOverride(std::filesystem::path path);
// changes the plugin path to the given path
void CoreSetPluginPathOverride(std::filesystem::path path);
// changes the shared data path to the given path
void CoreSetSharedDataPathOverride(std::filesystem::path path);
#endif // DIRECTORIES_HPP
+20 -3
View File
@@ -54,6 +54,7 @@ static void apply_coresettings_overlay(void)
CoreSettingsSetValue(SettingsID::Core_CountPerOp, CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOp));
CoreSettingsSetValue(SettingsID::Core_CountPerOpDenomPot, CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOpDenomPot));
CoreSettingsSetValue(SettingsID::Core_SiDmaDuration, CoreSettingsGetIntValue(SettingsID::CoreOverlay_SiDmaDuration));
CoreSettingsSetValue(SettingsID::Core_SaveFileNameFormat, CoreSettingsGetIntValue(SettingsID::CoreOverLay_SaveFileNameFormat));
}
static void apply_game_coresettings_overlay(void)
@@ -90,7 +91,8 @@ static void apply_game_coresettings_overlay(void)
bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64ddrom)
{
std::string error;
m64p_error ret;
m64p_error ret;
CoreRomType type;
if (!CoreOpenRom(n64rom))
{
@@ -126,8 +128,20 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
return false;
}
// set disk file in media loader
CoreMediaLoaderSetDiskFile(n64ddrom);
if (!CoreGetRomType(type))
{
CoreClearCheats();
CoreDetachPlugins();
CoreApplyPluginSettings();
CoreCloseRom();
return false;
}
// set disk file in media loader when ROM is a cartridge
if (type == CoreRomType::Cartridge)
{
CoreMediaLoaderSetDiskFile(n64ddrom);
}
// apply core settings overlay
apply_coresettings_overlay();
@@ -154,6 +168,9 @@ 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
+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
+177 -42
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"
@@ -16,11 +18,13 @@
#include "m64p/PluginApi.hpp"
#include "osal/osal_dynlib.hpp"
#include "osal/osal_files.hpp"
#include "m64p/PluginApi.cpp"
#include "m64p/Api.hpp"
#include <filesystem>
#include <cstring>
//
// Local Variables
@@ -28,6 +32,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 +106,80 @@ 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;
}
std::string get_plugin_path(CorePluginType type, std::string settingsValue)
{
std::string pluginPath;
std::string path;
std::string typeName;
// return an empty string when the value is empty
if (settingsValue.empty())
{
return std::string();
}
pluginPath = CoreGetPluginDirectory().string();
// if the full plugin path is in the settings value,
// we know it's the old type
if (settingsValue.find(pluginPath) != std::string::npos)
{
return settingsValue;
}
switch (type)
{
case CorePluginType::Rsp:
typeName = "RSP";
break;
case CorePluginType::Gfx:
typeName = "GFX";
break;
case CorePluginType::Audio:
typeName = "Audio";
break;
case CorePluginType::Input:
typeName = "Input";
break;
default:
return path;
}
path = pluginPath;
path += OSAL_FILES_DIR_SEPERATOR_STR;
path += typeName;
path += OSAL_FILES_DIR_SEPERATOR_STR;
path += settingsValue;
return path;
}
bool apply_plugin_settings(std::string pluginSettings[4])
{
std::string error;
@@ -112,14 +191,16 @@ bool apply_plugin_settings(std::string pluginSettings[4])
for (int i = 0; i < 4; i++)
{
settingValue = pluginSettings[i];
pluginType = (CorePluginType)(i + 1);
settingValue = get_plugin_path(pluginType, pluginSettings[i]);
if (settingValue.empty() ||
!std::filesystem::is_regular_file(settingValue))
{ // skip invalid setting value
continue;
}
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])
{
@@ -179,7 +260,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 (";
@@ -204,6 +285,78 @@ bool apply_plugin_settings(std::string pluginSettings[4])
return true;
}
bool open_plugin_config(CorePluginType type, bool romConfig)
{
std::string error;
m64p_error ret;
bool resumeEmulation = false;
m64p::PluginApi* plugin;
std::string functionName;
if (!romConfig && !CorePluginsHasConfig(type))
{
error = "open_plugin_config Failed: ";
error += get_plugin_type_name(type);
error += " doesn't have the config or config2 function!";
CoreSetError(error);
return false;
}
else if (romConfig && !CorePluginsHasROMConfig(type))
{
error = "open_plugin_config Failed: ";
error += get_plugin_type_name(type);
error += " doesn't support ROM specific configuration!";
CoreSetError(error);
return false;
}
// try to pause emulation,
// when emulation is running
// and try to resume afterwards
if (CoreIsEmulationRunning())
{
// only resume emulation
// after running the config function
// when pausing succeeds
resumeEmulation = CorePauseEmulation();
}
plugin = get_plugin(type);
// check if the plugin has the Config2
// or Config function, the Config2 function
// has priority
if (plugin->Config2 != nullptr)
{
ret = plugin->Config2(romConfig ? 1 : 0);
functionName = "Config2";
}
else
{
ret = plugin->Config();
functionName = "Config";
}
if (ret != M64ERR_SUCCESS)
{
error = "CorePluginsOpenConfig (";
error += get_plugin_type_name(type);
error += ")->";
error += functionName;
error += "() Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
// try to resume emulation when needed
if (resumeEmulation)
{
CoreResumeEmulation();
}
return ret == M64ERR_SUCCESS;
}
//
// Exported Functions
//
@@ -219,6 +372,7 @@ std::vector<CorePlugin> CoreGetAllPlugins(void)
for (const auto& entry : std::filesystem::recursive_directory_iterator(CoreGetPluginDirectory()))
{
std::string path = entry.path().string();
std::string file = entry.path().filename().string();
if (!entry.is_directory() &&
path.ends_with(OSAL_DYNLIB_LIB_EXT_STR))
{
@@ -239,7 +393,7 @@ std::vector<CorePlugin> CoreGetAllPlugins(void)
continue;
}
CorePlugin corePlugin = {path, plugin_name, plugin_type};
CorePlugin corePlugin = {file, plugin_name, plugin_type};
plugins.emplace_back(corePlugin);
}
}
@@ -302,52 +456,33 @@ bool CoreArePluginsReady(void)
bool CorePluginsHasConfig(CorePluginType type)
{
return get_plugin(type)->Config != nullptr;
m64p::PluginApi* plugin;
plugin = get_plugin(type);
return plugin->Config != nullptr ||
plugin->Config2 != nullptr;
}
bool CorePluginsOpenConfig(CorePluginType type)
{
std::string error;
m64p_error ret;
bool resumeEmulation = false;
return open_plugin_config(type, false);
}
if (!CorePluginsHasConfig(type))
{
error = "CorePluginsOpenConfig Failed: ";
error += get_plugin_type_name(type);
error += " doesn't have config function!";
CoreSetError(error);
return false;
}
bool CorePluginsHasROMConfig(CorePluginType type)
{
m64p::PluginApi* plugin;
// try to pause emulation,
// when emulation is running
// and try to resume afterwards
if (CoreIsEmulationRunning())
{
// only resume emulation
// after running the config function
// when pausing succeeds
resumeEmulation = CorePauseEmulation();
}
plugin = get_plugin(type);
ret = get_plugin(type)->Config();
if (ret != M64ERR_SUCCESS)
{
error = "CorePluginsOpenConfig (";
error += get_plugin_type_name(type);
error += ")->Config() Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return plugin->Config2 != nullptr &&
plugin->Config2HasRomConfig != nullptr &&
plugin->Config2HasRomConfig() > 0;
}
// try to resume emulation when needed
if (resumeEmulation)
{
CoreResumeEmulation();
}
return ret == M64ERR_SUCCESS;
bool CorePluginsOpenROMConfig(CorePluginType type)
{
return open_plugin_config(type, true);
}
bool CoreAttachPlugins(void)
+8
View File
@@ -52,6 +52,14 @@ bool CorePluginsHasConfig(CorePluginType type);
// used plugin of given type
bool CorePluginsOpenConfig(CorePluginType type);
// returns wether the currently used plugin
// of the given type has a ROM config GUI
bool CorePluginsHasROMConfig(CorePluginType type);
// opens the ROM config GUI for the currently
// used plugin of given type
bool CorePluginsOpenROMConfig(CorePluginType type);
// attaches all used plugins
bool CoreAttachPlugins(void);
+461 -28
View File
@@ -8,15 +8,29 @@
* 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"
// 7-Zip includes
#include "../3rdParty/7-Zip/C/7zTypes.h"
#include "../3rdParty/7-Zip/C/7z.h"
#include "../3rdParty/7-Zip/C/7zAlloc.h"
#include "../3rdParty/7-Zip/C/7zBuf.h"
#include "../3rdParty/7-Zip/C/7zCrc.h"
#include "../3rdParty/7-Zip/C/7zFile.h"
#include "../3rdParty/7-Zip/C/7zVersion.h"
#include <string>
#include <unzip.h>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
//
// Local Defines
@@ -28,31 +42,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 +193,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 +271,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);
@@ -178,19 +303,172 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
return false;
}
static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
static bool read_7zip_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;
const ISzAlloc alloc = { SzAlloc, SzFree };
const size_t bufSize = ((size_t)1 << 18);
ISzAlloc allocImp;
ISzAlloc allocTempImp;
CFileInStream archiveStream;
CLookToRead2 lookStream;
CSzArEx db;
SRes res;
// initialize allocator
allocImp = alloc;
allocTempImp = alloc;
// try to open file
#ifdef _WIN32
WRes wres = InFile_OpenW(&archiveStream.file, file.wstring().c_str());
#else
WRes wres = InFile_Open(&archiveStream.file, file.string().c_str());
#endif // _WIN32
if (wres != 0)
{
error = "read_7zip_file Failed: InFile_Open Failed: ";
error += std::to_string(wres);
CoreSetError(error);
return false;
}
// create vtables for streams
FileInStream_CreateVTable(&archiveStream);
archiveStream.wres = 0;
LookToRead2_CreateVTable(&lookStream, 0);
lookStream.buf = nullptr;
// allocate memory look reader
lookStream.buf = (Byte*)ISzAlloc_Alloc(&allocImp, bufSize);
if (lookStream.buf == nullptr)
{
error = "read_7zip_file Failed: ISzAlloc_Alloc Failed!";
CoreSetError(error);
return false;
}
// initialize look reader
lookStream.bufSize = bufSize;
lookStream.realStream = &archiveStream.vt;
LookToRead2_Init(&lookStream);
// initialize CRC table
CrcGenerateTable();
// initialize archive
SzArEx_Init(&db);
// try to open file
res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
if (res != SZ_OK)
{
error = "read_7zip_file Failed: SzArEx_Open Failed: ";
error += std::to_string(res);
CoreSetError(error);
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
return false;
}
for (int i = 0; i < db.NumFiles; i++)
{
size_t filename_size = 0;
uint16_t fileName[PATH_MAX];
// skip directories
if (SzArEx_IsDir(&db, i))
{
continue;
}
// skip when filename size exceeds our buffer size
filename_size = SzArEx_GetFileNameUtf16(&db, i, nullptr);
if (filename_size > PATH_MAX)
{
continue;
}
SzArEx_GetFileNameUtf16(&db, i, fileName);
std::filesystem::path fileNamePath((char16_t*)fileName);
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")
{
uint32_t blockIndex = 0xFFFFFFFF;
uint8_t* outBuffer = nullptr;
size_t outBufferSize = 0;
size_t offset = 0;
size_t outSizeProcessed = 0;
res = SzArEx_Extract(&db, &lookStream.vt, i,
&blockIndex, &outBuffer, &outBufferSize,
&offset, &outSizeProcessed,
&allocImp, &allocTempImp);
if (res != SZ_OK)
{
error = "read_7zip_file Failed: SzArEx_Extract Failed: ";
error += std::to_string(res);
CoreSetError(error);
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
File_Close(&archiveStream.file);
ISzAlloc_Free(&allocImp, outBuffer);
return false;
}
*size = outSizeProcessed;
// we have to memcpy it into buf, otherwise
// the free() in CoreOpenRom() crashes
*buf = (char*)malloc(outSizeProcessed);
memcpy(*buf, (outBuffer + offset), outSizeProcessed);
*extractedFileName = fileNamePath;
*isDisk = (fileExtension == ".ndd" || fileExtension == ".d64");
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
File_Close(&archiveStream.file);
ISzAlloc_Free(&allocImp, outBuffer);
return true;
}
}
// cleanup
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
File_Close(&archiveStream.file);
error = "read_7zip_file Failed: no valid ROMs found in 7zip!";
CoreSetError(error);
return false;
}
static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
{
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 +500,31 @@ 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 +533,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 +550,78 @@ 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" ||
file_extension == ".7z")
{
if (!read_zip_file(file, &buf, &buf_size))
std::filesystem::path extracted_file;
bool is_disk = false;
if (file_extension == ".zip")
{
return false;
if (!read_zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
{
return false;
}
}
else
{
if (!read_7zip_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 +629,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 +670,22 @@ bool CoreHasRomOpen(void)
return l_HasRomOpen;
}
bool CoreGetRomType(CoreRomType& type)
{
std::string error;
if (!l_HasRomOpen)
{
error = "CoreGetRomType Failed: ";
error += "cannot retrieve ROM type when no ROM has been opened!";
CoreSetError(error);
return false;
}
type = l_HasDisk ? CoreRomType::Disk : CoreRomType::Cartridge;
return true;
}
bool CoreCloseRom(void)
{
std::string error;
@@ -311,10 +709,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 +730,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);
// attempts to retrieve the ROM type
bool CoreGetRomType(CoreRomType& type);
// closes ROM
bool CoreCloseRom(void);
+94 -1
View File
@@ -21,6 +21,97 @@
#include "Error.hpp"
#include "Rom.hpp"
//
// Local Functions
//
static std::string get_gameid_from_header(m64p_rom_header header)
{
std::string gameID;
if (header.Manufacturer_ID == 0)
{
return "????";
}
gameID.push_back(char(ntohl(header.Manufacturer_ID)));
gameID.push_back(char(header.Cartridge_ID % 256));
gameID.push_back(char(header.Cartridge_ID / 256));
gameID.push_back(char(header.Country_code));
return gameID;
}
static std::string get_region_from_countrycode(char countryCode)
{
std::string region;
switch (countryCode)
{
case 'A':
region = "Region-Free";
break;
case 'B':
region = "Brazil";
break;
case 'C':
region = "China";
break;
case 'D':
region = "Germany";
break;
case 'E':
region = "North America";
break;
case 'F':
region = "France";
break;
case 'G':
region = "Gateway 64 (NTSC)";
break;
case 'H':
region = "Netherlands";
break;
case 'I':
region = "Italy";
break;
case 'J':
region = "Japan";
break;
case 'K':
region = "Korea";
break;
case 'L':
region = "Gateway 64 (PAL)";
break;
case 'N':
region = "Canada";
break;
case 'P':
case 'X':
region = "Europe/Australia";
break;
case 'S':
region = "Spain";
break;
case 'U':
region = "Australia";
break;
case 'W':
region = "Scandanavia";
break;
case 'Y':
case 'Z':
region = "Europe";
break;
default:
region = "Unknown";
break;
}
return region;
}
//
// Exported Functions
//
@@ -49,6 +140,8 @@ bool CoreGetCurrentRomHeader(CoreRomHeader& header)
header.CRC2 = ntohl(m64p_header.CRC2);
header.CountryCode = m64p_header.Country_code;
header.Name = CoreConvertStringEncoding((char*)m64p_header.Name, CoreStringEncoding::Shift_JIS);
header.GameID = get_gameid_from_header(m64p_header);
header.Region = get_region_from_countrycode((char)header.CountryCode);
return true;
}
+2
View File
@@ -19,6 +19,8 @@ struct CoreRomHeader
uint32_t CRC2;
uint32_t CountryCode;
std::string Name;
std::string GameID;
std::string Region;
};
// retrieves the currently opened ROM header
+109
View File
@@ -8,10 +8,33 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "SaveState.hpp"
#include "Directories.hpp"
#include "RomSettings.hpp"
#include "RomHeader.hpp"
#include "Error.hpp"
#include "Settings/Settings.hpp"
#include "m64p/Api.hpp"
#include <algorithm>
//
// Local Functions
//
// replaces all occurences of any chars in replace with c inside str
static void str_replace_chars(std::string& str, const std::string replace, const char c)
{
for (int i = 0; i < str.size(); i++)
{
char str_char = str.at(i);
if (replace.find(str_char) != std::string::npos)
{
str.at(i) = c;
}
}
}
//
// Exported Functions
//
@@ -59,6 +82,92 @@ int CoreGetSaveStateSlot(void)
return slot;
}
bool CoreGetSaveStatePath(int slot, std::filesystem::path& path)
{
// TODO: this should probably be an API function
// in mupen64plus-core instead
std::filesystem::path saveStatePath;
std::filesystem::path oldSaveStatePath;
std::string saveStateFileName;
std::filesystem::path saveStateExtension;
CoreRomHeader romHeader;
CoreRomSettings romSettings;
// attempt to retrieve the current
// rom header and settings
if (!CoreGetCurrentRomHeader(romHeader) ||
!CoreGetCurrentRomSettings(romSettings))
{
return false;
}
// retrieve save state directory
saveStatePath = CoreGetSaveStateDirectory();
saveStatePath += "/";
// construct extension
saveStateExtension = ".st";
saveStateExtension += std::to_string(slot);
// construct old save state path
oldSaveStatePath = saveStatePath;
oldSaveStatePath += romSettings.GoodName;
oldSaveStatePath += saveStateExtension;
// use old filename if it exists
if (std::filesystem::is_regular_file(oldSaveStatePath))
{
path = oldSaveStatePath;
return true;
}
// else use new filename
int format = CoreSettingsGetIntValue(SettingsID::Core_SaveFileNameFormat);
if (format == 0)
{
saveStatePath += romHeader.Name;
saveStatePath += saveStateExtension;
}
else
{
if (romSettings.GoodName.find("(unknown rom)") == std::string::npos)
{
if (romSettings.GoodName.size() < 32)
{
saveStatePath += romSettings.GoodName;
}
else
{
saveStatePath += romSettings.GoodName.substr(0, 32);
}
}
else if (!romHeader.Name.empty())
{
saveStatePath += romHeader.Name;
}
else
{
saveStatePath += "unknown";
}
saveStatePath += "-";
saveStatePath += romSettings.MD5.substr(0, 8);
saveStatePath += saveStateExtension;
}
// retrieve filename from path
saveStateFileName = saveStatePath.filename().string();
// sanitize filename
str_replace_chars(saveStateFileName, ":<>\"/\\|?*", '_');
// replace filename in path
saveStatePath.replace_filename(saveStateFileName);
path = saveStatePath;
return true;
}
bool CoreSaveState(void)
{
std::string error;
+4
View File
@@ -19,6 +19,10 @@ bool CoreSetSaveStateSlot(int slot);
// returns -1 on error
int CoreGetSaveStateSlot(void);
// retrieves the file path for
// the save state in the given slot
bool CoreGetSaveStatePath(int slot, std::filesystem::path& path);
// saves state
bool CoreSaveState(void);
+382 -70
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"
@@ -122,6 +122,7 @@ static std::vector<std::string> l_keyList;
#define SETTING_SECTION_GB SETTING_SECTION_CORE " Gameboy"
#define SETTING_SECTION_M64P "Core"
#define SETTING_SECTION_AUDIO SETTING_SECTION_GUI " - Audio Plugin"
#define SETTING_SECTION_INPUT SETTING_SECTION_GUI " - Input Plugin"
// retrieves l_Setting from settingId
static l_Setting get_setting(SettingsID settingId)
@@ -140,9 +141,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,49 +159,88 @@ 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_ToolbarArea:
setting = {SETTING_SECTION_GUI, "ToolbarArea", 0};
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_IconTheme:
setting = {SETTING_SECTION_GUI, "IconTheme", "Automatic"};
break;
case SettingsID::GUI_CheckForUpdates:
setting = {SETTING_SECTION_GUI, "CheckForUpdates", true};
break;
case SettingsID::GUI_LastUpdateCheck:
setting = {SETTING_SECTION_GUI, "LastUpdateCheck", ""};
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:
setting = {SETTING_SECTION_CORE, "GFX_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\GFX\\mupen64plus-video-GLideN64.dll",
"mupen64plus-video-GLideN64.dll",
#else
CoreGetPluginDirectory().string() + "/GFX/mupen64plus-video-GLideN64.so",
"mupen64plus-video-GLideN64.so",
#endif // _WIN32
};
break;
case SettingsID::Core_AUDIO_Plugin:
setting = {SETTING_SECTION_CORE, "AUDIO_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\Audio\\RMG-Audio.dll",
"RMG-Audio.dll",
#else
CoreGetPluginDirectory().string() + "/Audio/RMG-Audio.so",
"RMG-Audio.so",
#endif // _WIN32
};
break;
case SettingsID::Core_INPUT_Plugin:
setting = {SETTING_SECTION_CORE, "INPUT_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\Input\\RMG-Input.dll",
"RMG-Input.dll",
#else
CoreGetPluginDirectory().string() + "/Input/RMG-Input.so",
"RMG-Input.so",
#endif // _WIN32
};
break;
case SettingsID::Core_RSP_Plugin:
setting = {SETTING_SECTION_CORE, "RSP_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\RSP\\mupen64plus-rsp-hle.dll",
"mupen64plus-rsp-hle.dll",
#else
CoreGetPluginDirectory().string() + "/RSP/mupen64plus-rsp-hle.so",
"mupen64plus-rsp-hle.so",
#endif // _WIN32
};
break;
@@ -243,6 +280,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Core_SiDmaDuration:
setting = {SETTING_SECTION_M64P, "SiDmaDuration", -1};
break;
case SettingsID::Core_SaveFileNameFormat:
setting = {SETTING_SECTION_M64P, "SaveFilenameFormat", 1};
break;
case SettingsID::CoreOverlay_RandomizeInterrupt:
setting = {SETTING_SECTION_OVERLAY, "RandomizeInterrupt", true};
@@ -265,6 +305,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::CoreOverlay_SiDmaDuration:
setting = {SETTING_SECTION_OVERLAY, "SiDmaDuration", -1};
break;
case SettingsID::CoreOverLay_SaveFileNameFormat:
setting = {SETTING_SECTION_OVERLAY, "SaveFilenameFormat", 1};
break;
case SettingsID::Core_ScreenshotPath:
setting = {SETTING_SECTION_M64P, "ScreenshotPath", CoreGetDefaultScreenshotDirectory(), "", true};
@@ -359,17 +402,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"};
@@ -386,14 +426,47 @@ 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"};
case SettingsID::KeyBinding_SpeedFactor25:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor25", "Alt+0"};
break;
case SettingsID::KeyBinding_SpeedFactor50:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor50", "Alt+1"};
break;
case SettingsID::KeyBinding_SpeedFactor75:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor75", "Alt+2"};
break;
case SettingsID::KeyBinding_SpeedFactor100:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor100", "Alt+3"};
break;
case SettingsID::KeyBinding_SpeedFactor125:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor125", "Alt+4"};
break;
case SettingsID::KeyBinding_SpeedFactor150:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor150", "Alt+5"};
break;
case SettingsID::KeyBinding_SpeedFactor175:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor175", "Alt+6"};
break;
case SettingsID::KeyBinding_SpeedFactor200:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor200", "Alt+7"};
break;
case SettingsID::KeyBinding_SpeedFactor225:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor225", "Alt+8"};
break;
case SettingsID::KeyBinding_SpeedFactor250:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor250", "Alt+9"};
break;
case SettingsID::KeyBinding_SpeedFactor275:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor275", "Alt+["};
break;
case SettingsID::KeyBinding_SpeedFactor300:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor300", "Alt+]"};
break;
case SettingsID::KeyBinding_SaveState:
setting = {SETTING_SECTION_KEYBIND, "SaveState", "F5"};
@@ -413,9 +486,54 @@ 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;
case SettingsID::Keybinding_ViewLog:
setting = {SETTING_SECTION_KEYBIND, "ViewLog", "Ctrl+L"};
break;
case SettingsID::KeyBinding_GraphicsSettings:
setting = {SETTING_SECTION_KEYBIND, "GraphicsSettings", "Ctrl+G"};
break;
case SettingsID::KeyBinding_AudioSettings:
setting = {SETTING_SECTION_KEYBIND, "AudioSettings", "Ctrl+A"};
break;
case SettingsID::KeyBinding_RspSettings:
setting = {SETTING_SECTION_KEYBIND, "RspSettings", "Ctrl+R"};
break;
case SettingsID::KeyBinding_InputSettings:
setting = {SETTING_SECTION_KEYBIND, "InputSettings", "Ctrl+I"};
break;
case SettingsID::KeyBinding_Settings:
setting = {SETTING_SECTION_KEYBIND, "Settings", "Ctrl+T"};
break;
@@ -426,17 +544,44 @@ 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;
case SettingsID::RomBrowser_MaxItems:
setting = {SETTING_SECTION_ROMBROWSER, "MaxItems", 250};
break;
case SettingsID::RomBrowser_Columns:
setting = {SETTING_SECTION_ROMBROWSER, "Columns", std::vector<int>({0, 1, 2})};
case SettingsID::RomBrowser_ColumnVisibility:
setting = {SETTING_SECTION_ROMBROWSER, "ColumnVisibility", std::vector<int>({1, 1, 1, 0, 0, 0, 0, 0, 0})};
break;
case SettingsID::RomBrowser_ColumnOrder:
setting = {SETTING_SECTION_ROMBROWSER, "ColumnOrder", std::vector<int>({0, 1, 2, 3, 4, 5, 6, 7, 8})};
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, -1, -1, -1, -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:
@@ -471,6 +616,15 @@ static l_Setting get_setting(SettingsID settingId)
setting = {SETTING_SECTION_AUDIO, "Synchronize", false};
break;
case SettingsID::Input_Profiles:
setting = {SETTING_SECTION_INPUT, "Profiles", ""};
break;
case SettingsID::Input_UseProfile:
setting = {"", "UseProfile"};
break;
case SettingsID::Input_UseGameProfile:
setting = {"", "UseGameProfile"};
break;
case SettingsID::Input_PluggedIn:
setting = {"", "PluggedIn"};
break;
@@ -486,6 +640,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Input_Deadzone:
setting = {"", "Deadzone"};
break;
case SettingsID::Input_Sensitivity:
setting = {"", "Sensitivity"};
break;
case SettingsID::Input_Pak:
setting = {"", "Pak"};
break;
@@ -498,8 +655,11 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Input_RemoveDuplicateMappings:
setting = {"", "RemoveDuplicateMappings"};
break;
case SettingsID::Input_InvertAxis:
setting = {"", "InvertAxis"};
case SettingsID::Input_FilterEventsForButtons:
setting = {"", "FilterEventsForButtons"};
break;
case SettingsID::Input_FilterEventsForAxis:
setting = {"", "FilterEventsForAxis"};
break;
case SettingsID::Input_A_InputType:
setting = {"", "A_InputType"};
@@ -923,6 +1083,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
//
@@ -957,7 +1205,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;
}
@@ -996,7 +1244,7 @@ bool CoreSettingsUpgrade(void)
}
// save core version
CoreSettingsSetValue(SettingsID::GUI_Version, std::string(CORE_VERSION));
CoreSettingsSetValue(SettingsID::GUI_Version, CoreGetVersion());
CoreSettingsSave();
return true;
}
@@ -1037,7 +1285,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;
}
@@ -1060,6 +1308,27 @@ bool CoreSettingsSectionExists(std::string section)
return config_section_exists(section);
}
bool CoreSettingsRevertSection(std::string section)
{
std::string error;
m64p_error ret;
if (!m64p::Config.IsHooked())
{
return false;
}
ret = m64p::Config.RevertChanges(section.c_str());
if (ret != M64ERR_SUCCESS)
{
error = "CoreSettingsRevertSection m64p::Config.RevertChanges() Failed: ";
error = m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return ret == M64ERR_SUCCESS;
}
bool CoreSettingsDeleteSection(std::string section)
{
std::string error;
@@ -1121,10 +1390,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);
}
@@ -1157,10 +1435,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);
}
@@ -1189,10 +1476,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);
}
@@ -1265,6 +1561,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);
@@ -1305,25 +1607,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;
@@ -1352,27 +1660,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;
+17
View File
@@ -27,6 +27,9 @@ bool CoreSettingsSetupDefaults(void);
// returns whether a section exists
bool CoreSettingsSectionExists(std::string section);
// reverts section to the one from the settings
bool CoreSettingsRevertSection(std::string section);
// deletes given section
bool CoreSettingsDeleteSection(std::string section);
@@ -43,6 +46,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 +59,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 +73,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 +87,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 +100,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 +113,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 +127,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
+64 -11
View File
@@ -6,17 +6,29 @@ 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_ToolbarArea,
GUI_StatusBar,
GUI_Theme,
GUI_IconTheme,
GUI_CheckForUpdates,
GUI_LastUpdateCheck,
GUI_DiscordRpc,
GUI_Version,
// Core Plugin Settings
Core_GFX_Plugin,
Core_AUDIO_Plugin,
@@ -53,6 +65,7 @@ enum class SettingsID
Core_CountPerOp,
Core_CountPerOpDenomPot,
Core_SiDmaDuration,
Core_SaveFileNameFormat,
// (mupen64plus) Overlay Core Settings
CoreOverlay_RandomizeInterrupt,
@@ -62,6 +75,7 @@ enum class SettingsID
CoreOverlay_CountPerOp,
CoreOverlay_CountPerOpDenomPot,
CoreOverlay_SiDmaDuration,
CoreOverLay_SaveFileNameFormat,
// (mupen64plus) Core Directory Settings
Core_ScreenshotPath,
@@ -89,35 +103,69 @@ 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_SpeedFactor25,
KeyBinding_SpeedFactor50,
KeyBinding_SpeedFactor75,
KeyBinding_SpeedFactor100,
KeyBinding_SpeedFactor125,
KeyBinding_SpeedFactor150,
KeyBinding_SpeedFactor175,
KeyBinding_SpeedFactor200,
KeyBinding_SpeedFactor225,
KeyBinding_SpeedFactor250,
KeyBinding_SpeedFactor275,
KeyBinding_SpeedFactor300,
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_ViewLog,
KeyBinding_GraphicsSettings,
KeyBinding_AudioSettings,
KeyBinding_RspSettings,
KeyBinding_InputSettings,
KeyBinding_Settings,
// RomBrowser Settings
RomBrowser_Directory,
RomBrowser_Geometry,
RomBrowser_Maximized,
RomBrowser_Recursive,
RomBrowser_MaxItems,
RomBrowser_Columns,
RomBrowser_ColumnVisibility,
RomBrowser_ColumnOrder,
RomBrowser_ColumnSizes,
RomBrowser_SortAfterSearch,
RomBrowser_ViewMode,
RomBrowser_ListViewSortSection,
RomBrowser_ListViewSortOrder,
RomBrowser_GridViewIconWidth,
RomBrowser_GridViewIconHeight,
RomBrowser_GridViewUniformItemSizes,
// Settings Settings
Settings_HasForceUsedSetOnce,
@@ -133,16 +181,21 @@ enum class SettingsID
Audio_Synchronize,
// Input Plugin Settings
Input_Profiles,
Input_UseProfile,
Input_UseGameProfile,
Input_PluggedIn,
Input_DeviceType,
Input_DeviceName,
Input_DeviceNum,
Input_Deadzone,
Input_Sensitivity,
Input_Pak,
Input_GameboyRom,
Input_GameboySave,
Input_RemoveDuplicateMappings,
Input_InvertAxis,
Input_FilterEventsForButtons,
Input_FilterEventsForAxis,
Input_A_InputType,
Input_A_Name,
Input_A_Data,
+63
View File
@@ -0,0 +1,63 @@
/*
* 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 "SpeedFactor.hpp"
#include "Error.hpp"
#include "m64p/Api.hpp"
#include <string>
//
// Exported Functions
//
int CoreGetSpeedFactor(void)
{
std::string error;
m64p_error ret;
int value = 0;
if (!m64p::Core.IsHooked())
{
return 100;
}
ret = m64p::Core.DoCommand(M64CMD_CORE_STATE_QUERY, M64CORE_SPEED_FACTOR, &value);
if (ret != M64ERR_SUCCESS)
{
error = "CoreGetSpeedFactor: m64p::Core.DoCommand(M64CMD_CORE_STATE_QUERY) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return value;
}
bool CoreSetSpeedFactor(int factor)
{
std::string error;
m64p_error ret;
int value = factor;
if (!m64p::Core.IsHooked())
{
return false;
}
ret = m64p::Core.DoCommand(M64CMD_CORE_STATE_SET, M64CORE_SPEED_FACTOR, &value);
if (ret != M64ERR_SUCCESS)
{
error = "CoreSetSpeedFactor: m64p::Core.DoCommand(M64CMD_CORE_STATE_SET) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return ret == M64ERR_SUCCESS;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* 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_SPEEDFACTOR_HPP
#define CORE_SPEEDFACTOR_HPP
// returns the current speed factor
int CoreGetSpeedFactor(void);
// sets the speed factor
bool CoreSetSpeedFactor(int factor);
#endif // CORE_SPEEDFACTOR_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
+4
View File
@@ -28,6 +28,8 @@ bool PluginApi::Hook(m64p_dynlib_handle handle)
HOOK_FUNC(handle, Plugin, Startup);
HOOK_FUNC(handle, Plugin, Shutdown);
HOOK_FUNC_OPT(handle, Plugin, Config);
HOOK_FUNC_OPT(handle, Plugin, Config2);
HOOK_FUNC_OPT(handle, Plugin, Config2HasRomConfig);
HOOK_FUNC(handle, Plugin, GetVersion);
this->handle = handle;
@@ -40,6 +42,8 @@ bool PluginApi::Unhook(void)
UNHOOK_FUNC(Plugin, Startup);
UNHOOK_FUNC(Plugin, Shutdown);
UNHOOK_FUNC(Plugin, Config);
UNHOOK_FUNC(Plugin, Config2);
UNHOOK_FUNC(Plugin, Config2HasRomConfig);
UNHOOK_FUNC(Plugin, GetVersion);
this->handle = nullptr;
+2
View File
@@ -34,6 +34,8 @@ class PluginApi
ptr_PluginStartup Startup;
ptr_PluginShutdown Shutdown;
ptr_PluginConfig Config;
ptr_PluginConfig2 Config2;
ptr_PluginConfig2HasRomConfig Config2HasRomConfig;
ptr_PluginGetVersion GetVersion;
private:
+23
View File
@@ -21,6 +21,29 @@ typedef m64p_error (*ptr_PluginConfig)(void);
EXPORT m64p_error CALL PluginConfig(void);
#endif
/* PluginConfig2(int romConfig)
*
* This optional function opens a configuration GUI for the plugin
* https://github.com/mupen64plus/mupen64plus-core/pull/774
*
* romConfig argument determines if it should open the ROM specific config
*/
typedef m64p_error (*ptr_PluginConfig2)(int);
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL PluginConfig2(int);
#endif
/* PluginConfig2HasRomConfig(void)
*
* This optional function returns wether the plugin supports ROM specific config
* using PluginConfig2
*
*/
typedef int (*ptr_PluginConfig2HasRomConfig)(void);
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL PluginConfig2HasRomConfig(void);
#endif
#ifdef __cplusplus
}
#endif
+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)
+107 -27
View File
@@ -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, bool romConfig) : QDialog(parent)
{
this->setupUi(this);
this->setWindowIcon(QIcon(":Resource/RMG.png"));
@@ -41,7 +41,8 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(
for (int i = 0; i < this->tabWidget->count(); i++)
{
Widget::ControllerWidget* widget = new Widget::ControllerWidget(this, this->eventFilter);
widget->SetSettingsSection("Rosalie's Mupen GUI - Input Plugin Profile " + QString::number(i));
widget->SetOnlyLoadGameProfile(romConfig);
widget->SetSettingsSection("Player " + QString::number(i + 1), "Rosalie's Mupen GUI - Input Plugin Profile " + QString::number(i));
widget->LoadSettings();
this->tabWidget->widget(i)->layout()->addWidget(widget);
controllerWidgets.push_back(widget);
@@ -49,12 +50,19 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(
&MainDialog::on_ControllerWidget_CurrentInputDeviceChanged);
connect(widget, &Widget::ControllerWidget::RefreshInputDevicesButtonClicked, this,
&MainDialog::on_ControllerWidget_RefreshInputDevicesButtonClicked);
connect(widget, &Widget::ControllerWidget::UserProfileAdded, this,
&MainDialog::on_ControllerWidget_UserProfileAdded);
connect(widget, &Widget::ControllerWidget::UserProfileRemoved, this,
&MainDialog::on_ControllerWidget_UserProfileRemoved);
}
// always add keyboard device
for (auto& controllerWidget : this->controllerWidgets)
{
controllerWidget->AddInputDevice("Keyboard", -1);
controllerWidget->AddInputDevice("None", (int)InputDeviceType::None);
controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic);
controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard);
controllerWidget->SetInitialized(true);
}
// fill device list at least once
@@ -90,30 +98,50 @@ void MainDialog::openInputDevice(QString deviceName, int deviceNum)
{
SDL_JoystickID joystickId;
Widget::ControllerWidget* controllerWidget;
controllerWidget = controllerWidgets.at(this->tabWidget->currentIndex());
controllerWidget = this->controllerWidgets.at(this->tabWidget->currentIndex());
// we don't need to open a keyboard
if (deviceNum == -1)
if (deviceNum == (int)InputDeviceType::None ||
deviceNum == (int)InputDeviceType::Keyboard)
{
currentDeviceName = "";
currentDeviceNum = -1;
controllerWidget->SetCurrentJoystickID(-1);
this->currentDeviceName = "";
this->currentDeviceNum = deviceNum;
controllerWidget->SetCurrentJoystickID(this->currentDeviceNum);
return;
}
// handle automatic mode
if (deviceNum == (int)InputDeviceType::Automatic)
{
int currentIndex = this->tabWidget->currentIndex();
if (currentIndex < this->inputDeviceList.size())
{ // use device when there's one
deviceNum = this->inputDeviceList.at(currentIndex).deviceNum;
}
else
{ // no device found, fallback to keyboard
this->currentDeviceName = "";
this->currentDeviceNum = (int)InputDeviceType::Keyboard;
controllerWidget->SetCurrentJoystickID(this->currentDeviceNum);
return;
}
}
if (SDL_IsGameController(deviceNum) == SDL_TRUE)
{
currentJoystick = nullptr;
currentController = SDL_GameControllerOpen(deviceNum);
this->currentJoystick = nullptr;
this->currentController = SDL_GameControllerOpen(deviceNum);
}
else
{
currentJoystick = SDL_JoystickOpen(deviceNum);
currentController = nullptr;
this->currentJoystick = SDL_JoystickOpen(deviceNum);
this->currentController = nullptr;
}
currentDeviceNum = deviceNum;
this->currentDeviceNum = deviceNum;
joystickId = SDL_JoystickGetDeviceInstanceID(deviceNum);
controllerWidget->SetCurrentJoystickID(joystickId);
controllerWidget->SetIsCurrentJoystickGameController(currentController != nullptr);
}
void MainDialog::closeInputDevice()
@@ -193,8 +221,9 @@ void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*
this->closeInputDevice();
// only open device,
// when it's not a keyboard
if (deviceNum != -1)
// when needed
if (deviceNum != (int)InputDeviceType::None &&
deviceNum != (int)InputDeviceType::Keyboard)
{
this->openInputDevice(deviceName, deviceNum);
}
@@ -212,21 +241,54 @@ void MainDialog::on_ControllerWidget_RefreshInputDevicesButtonClicked()
this->sdlThread->SetAction(SDLThreadAction::GetInputDevices);
}
void MainDialog::on_ControllerWidget_UserProfileAdded(QString name, QString section)
{
for (auto& controllerWidget : this->controllerWidgets)
{
controllerWidget->AddUserProfile(name, section);
}
}
void MainDialog::on_ControllerWidget_UserProfileRemoved(QString name, QString section)
{
for (auto& controllerWidget : this->controllerWidgets)
{
controllerWidget->RemoveUserProfile(name, section);
}
}
void MainDialog::on_tabWidget_currentChanged(int index)
{
QString deviceName;
int deviceNum;
int deviceNum;
Widget::ControllerWidget* controllerWidget;
Widget::ControllerWidget* controllerWidget = controllerWidgets.at(index);
// save previous tab's user profile
if (previousTabWidgetIndex != -1 &&
previousTabWidgetIndex != index)
{
controllerWidget = controllerWidgets.at(previousTabWidgetIndex);
controllerWidget->SaveUserProfileSettings();
}
// update previous index
previousTabWidgetIndex = index;
// prepare switched tab
controllerWidget = controllerWidgets.at(index);
controllerWidget->ClearControllerImage();
this->closeInputDevice();
// re-load user profile settings
controllerWidget->LoadUserProfileSettings();
// retrieve current input device
controllerWidget->GetCurrentInputDevice(deviceName, deviceNum);
// only open device,
// when it's not a keyboard
if (deviceNum != -1)
// only open device when needed
if (deviceNum != (int)InputDeviceType::None &&
deviceNum != (int)InputDeviceType::Keyboard)
{
this->openInputDevice(deviceName, deviceNum);
}
@@ -309,19 +371,37 @@ void MainDialog::on_EventFilter_KeyReleased(QKeyEvent *event)
SDL_PeepEvents(&sdlEvent, 1, SDL_ADDEVENT, 0, 0);
}
void MainDialog::on_buttonBox_clicked(QAbstractButton *button)
void MainDialog::accept(void)
{
QPushButton *pushButton = (QPushButton *)button;
QPushButton *okButton = this->buttonBox->button(QDialogButtonBox::Ok);
Widget::ControllerWidget* controllerWidget;
int currentIndex = this->tabWidget->currentIndex();
if (pushButton == okButton)
for (int i = 0; i < this->controllerWidgets.count(); i++)
{
for (auto& controllerWidget : this->controllerWidgets)
if (i != currentIndex)
{
controllerWidget = this->controllerWidgets.at(i);
controllerWidget->SaveSettings();
}
CoreSettingsSave();
}
// the widget which has focus should be saved last
controllerWidget = this->controllerWidgets.at(currentIndex);
controllerWidget->SaveSettings();
CoreSettingsSave();
QDialog::accept();
}
void MainDialog::reject(void)
{
for (auto& controllerWidget : this->controllerWidgets)
{
controllerWidget->RevertSettings();
}
CoreSettingsSave();
QDialog::reject();
}
+11 -5
View File
@@ -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;
@@ -43,11 +43,13 @@ private:
bool updatingDeviceList = false;
QList<Widget::ControllerWidget*> controllerWidgets;
SDL_Joystick* currentJoystick = nullptr;
SDL_Joystick* currentJoystick = nullptr;
SDL_GameController* currentController = nullptr;
QString currentDeviceName;
int currentDeviceNum = 0;
int previousTabWidgetIndex = 0;
EventFilter* eventFilter;
void addInputDevice(QString, int);
@@ -57,7 +59,7 @@ private:
void closeInputDevice();
public:
MainDialog(QWidget *parent, Thread::SDLThread*);
MainDialog(QWidget *parent, Thread::SDLThread*, bool);
~MainDialog(void);
public slots:
@@ -65,7 +67,10 @@ public slots:
void on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*, QString, int);
void on_ControllerWidget_RefreshInputDevicesButtonClicked();
void on_ControllerWidget_UserProfileAdded(QString, QString);
void on_ControllerWidget_UserProfileRemoved(QString, QString);
void on_tabWidget_currentChanged(int);
void on_SDLThread_DeviceFound(QString, int);
@@ -75,7 +80,8 @@ private slots:
void on_EventFilter_KeyPressed(QKeyEvent *);
void on_EventFilter_KeyReleased(QKeyEvent *);
void on_buttonBox_clicked(QAbstractButton *);
void accept(void) Q_DECL_OVERRIDE;
void reject(void) Q_DECL_OVERRIDE;
};
}
@@ -18,11 +18,15 @@ 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);
this->filterEventsForButtonsCheckBox->setChecked(settings.FilterEventsForButtons);
this->filterEventsForAxisCheckBox->setChecked(settings.FilterEventsForAxis);
if (!CoreIsEmulationRunning() && !CoreIsEmulationPaused())
{
this->hideEmulationInfoText();
@@ -39,6 +43,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 +85,8 @@ 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->settings.FilterEventsForButtons = this->filterEventsForButtonsCheckBox->isChecked();
this->settings.FilterEventsForAxis = this->filterEventsForAxisCheckBox->isChecked();
}
this->accept();
@@ -24,7 +24,8 @@ struct OptionsDialogSettings
// UI settings
bool RemoveDuplicateMappings = false;
bool InvertAxis = false;
bool FilterEventsForButtons = true;
bool FilterEventsForAxis = true;
};
namespace UserInterface
@@ -43,6 +44,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>
@@ -203,9 +203,16 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="invertAxisCheckBox">
<widget class="QCheckBox" name="filterEventsForButtonsCheckBox">
<property name="text">
<string>Invert Axes Mapped To LRZ</string>
<string>Filter Events Based On Joystick Type For Buttons</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="filterEventsForAxisCheckBox">
<property name="text">
<string>Filter Events Based On Joystick Type For Axis</string>
</property>
</widget>
</item>
@@ -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
@@ -10,8 +10,8 @@
#include "ControllerImageWidget.hpp"
#include <QSvgRenderer>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <QPainter>
#include <QResizeEvent>
@@ -62,6 +62,15 @@ void ControllerImageWidget::SetDeadzone(int value)
}
}
void ControllerImageWidget::SetSensitivity(int value)
{
if (this->sensitivityValue != value)
{
this->sensitivityValue = value;
this->needImageUpdate = true;
}
}
void ControllerImageWidget::ClearControllerState()
{
// reset button state
@@ -125,6 +134,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";
@@ -152,27 +162,35 @@ void ControllerImageWidget::paintEvent(QPaintEvent *event)
renderer.setAspectRatioMode(Qt::AspectRatioMode::KeepAspectRatio);
QRectF rectF = renderer.viewBoxF();
double offsetx = 0, offsety = 0;
const int width = rectF.width();
const int height = rectF.height();
// we'll move the analog stick by a percentage
// of the total width/height from the image
const double maxOffsety = ((double)(height * 0.12265f) / 2);
const double maxOffsetx = maxOffsety;
const double dist = sqrt(pow(this->xAxisState, 2) + pow(this->yAxisState, 2));
const double absoluteMaxOffset = ((double)(height * 0.12265f) / 2);
// slope as in line gradient
const double offsetSlope = absoluteMaxOffset / 100;
// take sensitivity into account
const double sensitivityFactor = this->sensitivityValue / 100.0;
const double sensitivityAdjustedMaxOffset = absoluteMaxOffset * std::min(sensitivityFactor, 1.0);
double offsetDeadzone = this->deadzoneValue * sensitivityFactor * offsetSlope;
int offsetx = this->xAxisState * sensitivityFactor * offsetSlope;
int offsety = this->yAxisState * sensitivityFactor * offsetSlope;
const double offsetDist = sqrt(pow(offsetx, 2) + pow(offsety, 2));
// take deadzone into account
if (dist > this->deadzoneValue)
// deadzone grows with sensitivity such that the deadzone
// is always a percentage of the real stick range
if (offsetDist <= offsetDeadzone)
{
offsetx = (maxOffsetx / 100 * this->xAxisState);
offsety = (maxOffsety / 100 * this->yAxisState);
offsetx = 0;
offsety = 0;
}
// take circle range into account
if (dist > 100)
if (offsetDist > sensitivityAdjustedMaxOffset)
{
offsetx = (maxOffsetx / 100 * (this->xAxisState / dist * 100));
offsety = (maxOffsety / 100 * (this->yAxisState / dist * 100));
offsetx = (offsetx / offsetDist) * sensitivityAdjustedMaxOffset;
offsety = (offsety / offsetDist) * sensitivityAdjustedMaxOffset;
}
// adjust rect with offset
@@ -31,6 +31,8 @@ private:
int yAxisState = 0;
// deadzone value, 0-100
int deadzoneValue = 0;
// sensitivity value, 25-175
int sensitivityValue = 100;
bool needImageUpdate = false;
public:
@@ -41,6 +43,7 @@ public:
void SetXAxisState(int xAxis);
void SetYAxisState(int yAxis);
void SetDeadzone(int value);
void SetSensitivity(int value);
void ClearControllerState();
void UpdateImage();
File diff suppressed because it is too large Load Diff
@@ -10,7 +10,7 @@
#ifndef CONTROLLERWIDGET_H
#define CONTROLLERWIDGET_H
#include "CustomButton.hpp"
#include "MappingButton.hpp"
#include "ControllerImageWidget.hpp"
#include "UserInterface/EventFilter.hpp"
@@ -34,28 +34,35 @@ class ControllerWidget : public QWidget, Ui::ControllerWidget
Q_OBJECT
private:
bool initialized = false;
QString settingsSection;
QString gameSection;
OptionsDialogSettings optionsDialogSettings;
QList<QString> inputDeviceNameList;
CustomButton* currentButton = nullptr;
MappingButton* currentButton = nullptr;
bool addMappingToButton = false;
QList<QString> profiles;
QList<QString> removedProfiles;
QList<QString> addedProfiles;
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,11 +72,11 @@ private:
QList<buttonWidgetMapping> buttonWidgetMappings;
QList<axisWidgetMapping> joystickWidgetMappings;
QList<buttonSettingMapping> buttonSettingMappings;
QList<CustomButton*> setupButtonWidgets;
int currentSetupButtonWidgetIndex = 0;
bool currentInSetup = false;
QList<MappingButton*> setupButtonWidgets;
void initializeButtons();
void initializeMappingButtons();
void initializeProfileButtons();
void initializeMiscButtons();
bool isCurrentDeviceKeyboard();
bool isCurrentDeviceNotFound();
@@ -77,11 +84,27 @@ private:
void disableAllChildren();
void enableAllChildren();
void removeDuplicates(CustomButton* button);
void removeDuplicates(MappingButton* button);
QString getCurrentSettingsSection();
SDL_JoystickID currentJoystickId = -1;
QString getUserProfileSectionName(QString profile);
bool isSectionUserProfile(QString section);
bool isSectionGameProfile(QString section);
void setPluggedIn(bool value);
bool hasAnyGameSettingChanged(void);
void showErrorMessage(QString text, QString details = "");
SDL_JoystickID currentJoystickId = -1;
bool isCurrentJoystickGameController = false;
int previousProfileComboBoxIndex = -1;
bool onlyLoadGameProfile = false;
public:
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
@@ -97,40 +120,60 @@ public:
void GetCurrentInputDevice(QString& deviceName, int& deviceNum, bool ignoreDeviceNotFound = false);
bool IsPluggedIn();
void SetSettingsSection(QString section);
void SetOnlyLoadGameProfile(bool value);
void SetSettingsSection(QString profile, QString section);
void SetInitialized(bool value);
void LoadSettings();
void LoadSettings(QString section);
void LoadSettings(QString section, bool loadUserProfile = false);
void LoadUserProfileSettings();
void SaveDefaultSettings();
void SaveSettings();
void SaveUserProfileSettings();
void SaveSettings(QString section);
void RevertSettings();
void SetCurrentJoystickID(SDL_JoystickID joystickId);
void SetIsCurrentJoystickGameController(bool isGameController);
void AddUserProfile(QString name, QString section);
void RemoveUserProfile(QString name, QString section);
private slots:
void on_deadZoneSlider_valueChanged(int value);
void on_analogStickSensitivitySlider_valueChanged(int value);
void on_profileComboBox_currentIndexChanged(int value);
void on_inputDeviceComboBox_currentIndexChanged(int value);
void on_inputDeviceRefreshButton_clicked();
void on_controllerPluggedCheckBox_toggled(bool value);
void on_addProfileButton_clicked();
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:
void CurrentInputDeviceChanged(ControllerWidget* widget, QString deviceName, int deviceNum);
void RefreshInputDevicesButtonClicked();
void UserProfileAdded(QString name, QString section);
void UserProfileRemoved(QString name, QString section);
};
}
}
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,250 @@
/*
* 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);
this->initialSize = this->size();
}
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->initialSize.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,84 @@
/*
* 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:
QSize initialSize;
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
+1 -1
View File
@@ -83,7 +83,7 @@ void InputDevice::OpenDevice(std::string name, int num)
// wait until SDLThread is done first
while (this->sdlThread->GetCurrentAction() != SDLThreadAction::None)
{
QThread::msleep(50);
QThread::msleep(5);
}
this->foundDevicesWithNameMatch.clear();
+7
View File
@@ -31,6 +31,13 @@ enum class N64ControllerButton
Invalid
};
enum class InputDeviceType
{
None = -3,
Automatic = -2,
Keyboard = -1
};
enum class InputType
{
Keyboard = -1,
+312 -122
View File
@@ -21,7 +21,7 @@
#include <QApplication>
#include <SDL.h>
#include <iostream>
#include <algorithm>
#include <chrono>
//
@@ -49,15 +49,18 @@
struct InputMapping
{
InputType Type = InputType::Invalid;
int Data = 0;
int ExtraData = 0;
std::vector<std::string> Name;
std::vector<int> Type;
std::vector<int> Data;
std::vector<int> ExtraData;
int Count = 0;
};
struct InputProfile
{
bool PluggedIn = false;
int DeadzoneValue = 0;
int SensitivityValue = 100;
N64ControllerPak ControllerPak = N64ControllerPak::None;
@@ -120,11 +123,27 @@ static bool l_KeyboardState[SDL_NUM_SCANCODES];
//
static void load_inputmapping_settings(InputMapping* mapping, std::string section,
SettingsID inputTypeSettingsId, SettingsID dataSettingsId, SettingsID extraDataSettingsId)
SettingsID inputNameSettingsId, SettingsID inputTypeSettingsId,
SettingsID dataSettingsId, SettingsID extraDataSettingsId)
{
mapping->Type = (InputType)CoreSettingsGetIntValue(inputTypeSettingsId, section);
mapping->Data = CoreSettingsGetIntValue(dataSettingsId, section);
mapping->ExtraData = CoreSettingsGetIntValue(extraDataSettingsId, section);
mapping->Name = CoreSettingsGetStringListValue(inputNameSettingsId, 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()));
// check if mapping is old profile type,
// it should be true when the minimum of the lengths
// of all int lists is 0, and the name isn't empty or whitespace
if (mapping->Count == 0 &&
!mapping->Name.empty() && !mapping->Name.at(0).empty() &&
mapping->Name.at(0).find_first_not_of(' ') != std::string::npos)
{
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)
@@ -132,26 +151,60 @@ static void load_settings(void)
std::string gameId;
CoreRomSettings romSettings;
std::string userProfileSectionBase = "Rosalie's Mupen GUI - Input Plugin User Profile";
std::vector<std::string> userProfiles;
std::vector<std::string>::iterator userProfilesIter;
// try to retrieve current ROM settings
if (CoreGetCurrentRomSettings(romSettings))
{
gameId = romSettings.MD5;
}
// retrieve all user profiles
userProfiles = CoreSettingsGetStringListValue(SettingsID::Input_Profiles);
for (int i = 0; i < NUM_CONTROLLERS; i++)
{
InputProfile* profile = &l_InputProfiles[i];
std::string section = "Rosalie's Mupen GUI - Input Plugin Profile " + std::to_string(i);
std::string section = "Rosalie's Mupen GUI - Input Plugin Profile " + std::to_string(i);
std::string gameSection = section + " Game " + gameId;
std::string userProfileSection;
std::string userProfileName;
// when a user profile has been specified,
// ensure it exists in the profile list and
// in the settings, if it does,
// use that user profile
userProfileName = CoreSettingsGetStringValue(SettingsID::Input_UseProfile, section);
if (!userProfileName.empty())
{
userProfilesIter = std::find(userProfiles.begin(), userProfiles.end(), userProfileName);
if (userProfilesIter != userProfiles.end())
{
userProfileSection = userProfileSectionBase;
userProfileSection += " \"" + userProfileName + "\"";
if (CoreSettingsSectionExists(userProfileSection))
{
section = userProfileSection;
}
}
}
// if game ID was retrieved,
// check if game section exists, if it does
// use that section instead of the main section
// check if game section exists,
// if it does, check if the 'UseGameProfile' key exists,
// if it doesn't then use the profile, else
// check if the value is true
if (!gameId.empty())
{
if (CoreSettingsSectionExists(gameSection))
{
section = gameSection;
if (!CoreSettingsKeyExists(gameSection, "UseGameProfile") ||
CoreSettingsGetBoolValue(SettingsID::Input_UseGameProfile, gameSection))
{
section = gameSection;
}
}
}
@@ -171,25 +224,35 @@ static void load_settings(void)
profile->GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
profile->GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
// keep compatibility with profiles before version v0.3.9
if (CoreSettingsKeyExists(section, "Sensitivity"))
{
profile->SensitivityValue = CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section);
}
else
{
profile->SensitivityValue = 100;
}
// load inputmapping settings
load_inputmapping_settings(&profile->Button_A, section, SettingsID::Input_A_InputType, SettingsID::Input_A_Data, SettingsID::Input_A_ExtraData);
load_inputmapping_settings(&profile->Button_B, section, SettingsID::Input_B_InputType, SettingsID::Input_B_Data, SettingsID::Input_B_ExtraData);
load_inputmapping_settings(&profile->Button_Start, section, SettingsID::Input_Start_InputType, SettingsID::Input_Start_Data, SettingsID::Input_Start_ExtraData);
load_inputmapping_settings(&profile->Button_DpadUp, section, SettingsID::Input_DpadUp_InputType, SettingsID::Input_DpadUp_Data, SettingsID::Input_DpadUp_ExtraData);
load_inputmapping_settings(&profile->Button_DpadDown, section, SettingsID::Input_DpadDown_InputType, SettingsID::Input_DpadDown_Data, SettingsID::Input_DpadDown_ExtraData);
load_inputmapping_settings(&profile->Button_DpadLeft, section, SettingsID::Input_DpadLeft_InputType, SettingsID::Input_DpadLeft_Data, SettingsID::Input_DpadLeft_ExtraData);
load_inputmapping_settings(&profile->Button_DpadRight, section, SettingsID::Input_DpadRight_InputType, SettingsID::Input_DpadRight_Data, SettingsID::Input_DpadRight_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonUp, section, SettingsID::Input_CButtonUp_InputType, SettingsID::Input_CButtonUp_Data, SettingsID::Input_CButtonUp_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonDown, section, SettingsID::Input_CButtonDown_InputType, SettingsID::Input_CButtonDown_Data, SettingsID::Input_CButtonDown_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonLeft, section, SettingsID::Input_CButtonLeft_InputType, SettingsID::Input_CButtonLeft_Data, SettingsID::Input_CButtonLeft_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonRight, section, SettingsID::Input_CButtonRight_InputType, SettingsID::Input_CButtonRight_Data, SettingsID::Input_CButtonRight_ExtraData);
load_inputmapping_settings(&profile->Button_LeftTrigger, section, SettingsID::Input_LeftTrigger_InputType, SettingsID::Input_LeftTrigger_Data, SettingsID::Input_LeftTrigger_ExtraData);
load_inputmapping_settings(&profile->Button_RightTrigger, section, SettingsID::Input_RightTrigger_InputType, SettingsID::Input_RightTrigger_Data, SettingsID::Input_RightTrigger_ExtraData);
load_inputmapping_settings(&profile->Button_ZTrigger, section, SettingsID::Input_ZTrigger_InputType, SettingsID::Input_ZTrigger_Data, SettingsID::Input_ZTrigger_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Up, section, SettingsID::Input_AnalogStickUp_InputType, SettingsID::Input_AnalogStickUp_Data, SettingsID::Input_AnalogStickUp_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Down, section, SettingsID::Input_AnalogStickDown_InputType, SettingsID::Input_AnalogStickDown_Data, SettingsID::Input_AnalogStickDown_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Left, section, SettingsID::Input_AnalogStickLeft_InputType, SettingsID::Input_AnalogStickLeft_Data, SettingsID::Input_AnalogStickLeft_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Right, section, SettingsID::Input_AnalogStickRight_InputType, SettingsID::Input_AnalogStickRight_Data, SettingsID::Input_AnalogStickRight_ExtraData);
load_inputmapping_settings(&profile->Button_A, section, SettingsID::Input_A_Name, SettingsID::Input_A_InputType, SettingsID::Input_A_Data, SettingsID::Input_A_ExtraData);
load_inputmapping_settings(&profile->Button_B, section, SettingsID::Input_B_Name, SettingsID::Input_B_InputType, SettingsID::Input_B_Data, SettingsID::Input_B_ExtraData);
load_inputmapping_settings(&profile->Button_Start, section, SettingsID::Input_Start_Name, SettingsID::Input_Start_InputType, SettingsID::Input_Start_Data, SettingsID::Input_Start_ExtraData);
load_inputmapping_settings(&profile->Button_DpadUp, section, SettingsID::Input_DpadUp_Name, SettingsID::Input_DpadUp_InputType, SettingsID::Input_DpadUp_Data, SettingsID::Input_DpadUp_ExtraData);
load_inputmapping_settings(&profile->Button_DpadDown, section, SettingsID::Input_DpadDown_Name, SettingsID::Input_DpadDown_InputType, SettingsID::Input_DpadDown_Data, SettingsID::Input_DpadDown_ExtraData);
load_inputmapping_settings(&profile->Button_DpadLeft, section, SettingsID::Input_DpadLeft_Name, SettingsID::Input_DpadLeft_InputType, SettingsID::Input_DpadLeft_Data, SettingsID::Input_DpadLeft_ExtraData);
load_inputmapping_settings(&profile->Button_DpadRight, section, SettingsID::Input_DpadRight_Name, SettingsID::Input_DpadRight_InputType, SettingsID::Input_DpadRight_Data, SettingsID::Input_DpadRight_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonUp, section, SettingsID::Input_CButtonUp_Name, SettingsID::Input_CButtonUp_InputType, SettingsID::Input_CButtonUp_Data, SettingsID::Input_CButtonUp_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonDown, section, SettingsID::Input_CButtonDown_Name, SettingsID::Input_CButtonDown_InputType, SettingsID::Input_CButtonDown_Data, SettingsID::Input_CButtonDown_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonLeft, section, SettingsID::Input_CButtonLeft_Name, SettingsID::Input_CButtonLeft_InputType, SettingsID::Input_CButtonLeft_Data, SettingsID::Input_CButtonLeft_ExtraData);
load_inputmapping_settings(&profile->Button_CButtonRight, section, SettingsID::Input_CButtonRight_Name, SettingsID::Input_CButtonRight_InputType, SettingsID::Input_CButtonRight_Data, SettingsID::Input_CButtonRight_ExtraData);
load_inputmapping_settings(&profile->Button_LeftTrigger, section, SettingsID::Input_LeftTrigger_Name, SettingsID::Input_LeftTrigger_InputType, SettingsID::Input_LeftTrigger_Data, SettingsID::Input_LeftTrigger_ExtraData);
load_inputmapping_settings(&profile->Button_RightTrigger, section, SettingsID::Input_RightTrigger_Name, SettingsID::Input_RightTrigger_InputType, SettingsID::Input_RightTrigger_Data, SettingsID::Input_RightTrigger_ExtraData);
load_inputmapping_settings(&profile->Button_ZTrigger, section, SettingsID::Input_ZTrigger_Name, SettingsID::Input_ZTrigger_InputType, SettingsID::Input_ZTrigger_Data, SettingsID::Input_ZTrigger_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Up, section, SettingsID::Input_AnalogStickUp_Name, SettingsID::Input_AnalogStickUp_InputType, SettingsID::Input_AnalogStickUp_Data, SettingsID::Input_AnalogStickUp_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Down, section, SettingsID::Input_AnalogStickDown_Name, SettingsID::Input_AnalogStickDown_InputType, SettingsID::Input_AnalogStickDown_Data, SettingsID::Input_AnalogStickDown_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Left, section, SettingsID::Input_AnalogStickLeft_Name, SettingsID::Input_AnalogStickLeft_InputType, SettingsID::Input_AnalogStickLeft_Data, SettingsID::Input_AnalogStickLeft_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Right, section, SettingsID::Input_AnalogStickRight_Name, SettingsID::Input_AnalogStickRight_InputType, SettingsID::Input_AnalogStickRight_Data, SettingsID::Input_AnalogStickRight_ExtraData);
}
}
@@ -259,15 +322,90 @@ static void apply_gameboy_settings(void)
CoreSettingsSave();
}
static void setup_device_automatic(int num, InputProfile* profile)
{
static int previousSdlDeviceNum = -1;
// reset variable when needed
if (num == 0)
{
previousSdlDeviceNum = -1;
}
bool foundSdlDevice = false;
SDL_GameController* sdlGameController = nullptr;
SDL_Joystick* sdlJoystick = nullptr;
std::string sdlDeviceName;
for (int i = (previousSdlDeviceNum + 1); i < SDL_NumJoysticks(); i++)
{
if (SDL_IsGameController(i))
{
sdlGameController = SDL_GameControllerOpen(i);
if (sdlGameController != nullptr)
{
sdlDeviceName = SDL_GameControllerName(sdlGameController);
SDL_GameControllerClose(sdlGameController);
profile->DeviceNum = i;
profile->DeviceName = sdlDeviceName;
previousSdlDeviceNum = i;
foundSdlDevice = true;
break;
}
}
else
{
sdlJoystick = SDL_JoystickOpen(i);
if (sdlJoystick != nullptr)
{
sdlDeviceName = SDL_JoystickName(sdlJoystick);
SDL_JoystickClose(sdlJoystick);
profile->DeviceNum = i;
profile->DeviceName = sdlDeviceName;
previousSdlDeviceNum = i;
foundSdlDevice = true;
break;
}
}
}
if (!foundSdlDevice)
{ // fallback to keyboard
if (num == 0)
{
profile->DeviceNum = (int)InputDeviceType::Keyboard;
}
else
{
profile->PluggedIn = false;
// only override present in core
// when we have the control info
if (l_HasControlInfo)
{
l_ControlInfo.Controls[num].Present = 0;
}
}
}
}
static void open_controllers(void)
{
// force re-fresh joystick list
SDL_JoystickUpdate();
for (int i = 0; i < NUM_CONTROLLERS; i++)
{
InputProfile* profile = &l_InputProfiles[i];
profile->InputDevice.CloseDevice();
if (profile->DeviceNum != -1)
if (profile->DeviceNum == (int)InputDeviceType::Automatic)
{
setup_device_automatic(i, profile);
}
if (profile->DeviceNum != (int)InputDeviceType::Keyboard)
{
profile->InputDevice.OpenDevice(profile->DeviceName, profile->DeviceNum);
}
@@ -279,95 +417,125 @@ static void close_controllers(void)
for (int i = 0; i < NUM_CONTROLLERS; i++)
{
InputProfile* profile = &l_InputProfiles[i];
profile->InputDevice.CloseDevice();
}
}
static int get_button_state(InputProfile* profile, InputMapping* inputMapping)
static int get_button_state(InputProfile* profile, const 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)
static double get_axis_state(InputProfile* profile, const InputMapping* inputMapping, const int direction, const double value, bool& useButtonMapping)
{
switch (inputMapping->Type)
double axis_state = value;
bool button_state = false;
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])
{
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)
case InputType::GamepadButton:
{
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)
button_state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);;
} break;
case InputType::GamepadAxis:
{
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;
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;
axis_state = axis_value;
}
} break;
case InputType::JoystickButton:
{
button_state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);;
} 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;
axis_state = axis_value;
}
} break;
case InputType::Keyboard:
{
button_state |= l_KeyboardState[data];
} break;
default:
break;
}
}
return value;
// when a button has been mapped
// to an axis, we should prioritize
// the button when it's been pressed
if (button_state)
{
useButtonMapping = true;
return direction;
}
else if (!useButtonMapping)
{
return axis_state;
}
else
{
return value;
}
}
static double simulate_deadzone(double n64InputAxis, double maxAxis, int deadzone, double axisRange)
static double simulate_deadzone(const double n64InputAxis, const double maxAxis, const int deadzone, const double axisRange)
{
double axisAbsolute = std::abs(n64InputAxis);
if (axisAbsolute < deadzone)
if (axisAbsolute <= deadzone)
{
axisAbsolute = 0; // No input when inside deadzone
}
@@ -380,16 +548,17 @@ static double simulate_deadzone(double n64InputAxis, double maxAxis, int deadzon
return axisAbsolute;
}
// Credit: MerryMage
static void simulate_octagon(double inputX, double inputY, double deadzoneFactor, int& outputX, int& outputY)
// Credit: MerryMage & fzurita
static void simulate_octagon(const double inputX, const double inputY, const double deadzoneFactor, const double sensitivityFactor, int& outputX, int& outputY)
{
double maxAxis = N64_AXIS_PEAK;
double maxDiagonal = MAX_DIAGONAL_VALUE;
int deadzone = static_cast<int>(deadzoneFactor * N64_AXIS_PEAK);
double axisRange = maxAxis - deadzone;
// don't increase emulated range at higher than 100% sensitivity
const double maxAxis = N64_AXIS_PEAK * std::min(sensitivityFactor, 1.0);
const double maxDiagonal = MAX_DIAGONAL_VALUE * std::min(sensitivityFactor, 1.0);
const int deadzone = (int)(deadzoneFactor * N64_AXIS_PEAK * sensitivityFactor);
const double axisRange = maxAxis - deadzone;
// scale to [-maxAxis, maxAxis]
double ax = inputX * maxAxis;
double ay = inputY * maxAxis;
double ax = std::min(inputX * sensitivityFactor, 1.0) * maxAxis;
double ay = std::min(inputY * sensitivityFactor, 1.0) * maxAxis;
// check whether (ax, ay) is within the circle of radius MAX_AXIS
double len = std::sqrt(ax*ax + ay*ay);
@@ -410,18 +579,18 @@ static void simulate_octagon(double inputX, double inputY, double deadzoneFactor
// bound diagonals to an octagonal range [-69, 69]
if (ax != 0.0 && ay != 0.0)
{
double slope = ay / ax;
double edgex = copysign(maxAxis / (std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal), ax);
double edgey = copysign(std::min(std::abs(edgex * slope), maxAxis / (1.0 / std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal)), ay);
const double slope = ay / ax;
double edgex = std::copysign(maxAxis / (std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal), ax);
const double edgey = std::copysign(std::min(std::abs(edgex * slope), maxAxis / (1.0 / std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal)), ay);
edgex = edgey / slope;
double scale = std::sqrt(edgex*edgex + edgey*edgey) / maxAxis;
const double scale = std::sqrt(edgex*edgex + edgey*edgey) / maxAxis;
ax *= scale;
ay *= scale;
}
outputX = static_cast<int>(ax);
outputY = static_cast<int>(ay);
outputX = (int)ax;
outputY = (int)ay;
}
static unsigned char data_crc(unsigned char *data, int length)
@@ -450,18 +619,26 @@ static unsigned char data_crc(unsigned char *data, int length)
void sdl_init()
{
for (int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
std::filesystem::path gameControllerDbPath;
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
{
if (!SDL_WasInit(subsystem))
{
SDL_InitSubSystem(subsystem);
}
}
gameControllerDbPath = CoreGetSharedDataDirectory();
gameControllerDbPath += "/gamecontrollerdb.txt";
// load mappings from file
SDL_GameControllerAddMappingsFromFile(gameControllerDbPath.string().c_str());
}
void sdl_quit()
{
for (int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_HAPTIC})
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_HAPTIC})
{
if (SDL_WasInit(subsystem))
{
@@ -554,7 +731,7 @@ EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *pluginType, int *plugi
// Custom Plugin Functions
//
EXPORT m64p_error CALL PluginConfig()
EXPORT m64p_error CALL PluginConfig2(int romConfig)
{
if (l_SDLThread == nullptr)
{
@@ -566,11 +743,17 @@ EXPORT m64p_error CALL PluginConfig()
l_SDLThread->SetAction(SDLThreadAction::SDLPumpEvents);
UserInterface::MainDialog dialog(nullptr, l_SDLThread);
UserInterface::MainDialog dialog(nullptr, l_SDLThread, romConfig);
dialog.exec();
l_SDLThread->SetAction(SDLThreadAction::None);
// wait until it's done pumping events
while (l_SDLThread->GetCurrentAction() == SDLThreadAction::SDLPumpEvents)
{
QThread::msleep(5);
}
// reload settings
load_settings();
@@ -586,6 +769,11 @@ EXPORT m64p_error CALL PluginConfig()
return M64ERR_SUCCESS;
}
EXPORT int CALL PluginConfig2HasRomConfig(void)
{
return 1;
}
//
// Input Plugin Functions
//
@@ -660,13 +848,13 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
// check if device has been disconnected,
// if it has, try to open it again,
// only do this every 2 seconds to prevent lag
const auto currentTime = std::chrono::high_resolution_clock::now();
const auto currentTime = std::chrono::high_resolution_clock::now();
const int secondsPassed = std::chrono::duration_cast<std::chrono::seconds>(currentTime - profile->LastDeviceCheckTime).count();
if (secondsPassed >= 2)
{
profile->LastDeviceCheckTime = currentTime;
if (profile->DeviceNum != -1)
if (profile->DeviceNum != (int)InputDeviceType::Keyboard)
{
if (profile->InputDevice.IsOpeningDevice())
{
@@ -676,7 +864,6 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
if (!profile->InputDevice.HasOpenDevice() || !profile->InputDevice.IsAttached())
{
profile->InputDevice.OpenDevice(profile->DeviceName, profile->DeviceNum);
return;
}
}
}
@@ -697,16 +884,18 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
Keys->Z_TRIG = get_button_state(profile, &profile->Button_ZTrigger);
double inputX = 0, inputY = 0;
inputY = get_axis_state(profile, &profile->AnalogStick_Up, 1, inputY);
inputY = get_axis_state(profile, &profile->AnalogStick_Down, -1, inputY);
inputX = get_axis_state(profile, &profile->AnalogStick_Left, -1, inputX);
inputX = get_axis_state(profile, &profile->AnalogStick_Right, 1, inputX);
bool useButtonMapping = false;
inputY = get_axis_state(profile, &profile->AnalogStick_Up, 1, inputY, useButtonMapping);
inputY = get_axis_state(profile, &profile->AnalogStick_Down, -1, inputY, useButtonMapping);
inputX = get_axis_state(profile, &profile->AnalogStick_Left, -1, inputX, useButtonMapping);
inputX = get_axis_state(profile, &profile->AnalogStick_Right, 1, inputX, useButtonMapping);
int octagonX = 0, octagonY = 0;
simulate_octagon(
inputX, // inputX
inputY, // inputY
profile->DeadzoneValue / 100.0, // deadzoneFactor
profile->SensitivityValue / 100.0, // sensitivityFactor
octagonX, // outputX
octagonY // outputY
);
@@ -722,7 +911,7 @@ EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
l_KeyboardState[i] = 0;
}
l_ControlInfo = ControlInfo;
l_ControlInfo = ControlInfo;
l_HasControlInfo = true;
// load settings
@@ -746,6 +935,7 @@ EXPORT int CALL RomOpen(void)
EXPORT void CALL RomClosed(void)
{
l_HasControlInfo = false;
close_controllers();
}
+43 -18
View File
@@ -5,30 +5,45 @@ 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(Qt5 COMPONENTS Network REQUIRED)
add_definitions(-DUPDATER)
find_package(Qt6 COMPONENTS Network REQUIRED)
add_definitions(-DUPDATER)
endif(UPDATER)
if (APPIMAGE_UPDATER)
add_definitions(-DAPPIMAGE_UPDATER)
endif(APPIMAGE_UPDATER)
if (DISCORD_RPC)
add_definitions(-DDISCORD_RPC)
add_definitions(-DDISCORD_RPC)
endif(DISCORD_RPC)
if (FORCE_XCB)
add_definitions(-DFORCE_XCB)
endif(FORCE_XCB)
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
@@ -39,6 +54,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
@@ -46,31 +63,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
)
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
@@ -78,11 +102,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 Qt5::Network)
target_link_libraries(RMG Qt6::Network)
endif(UPDATER)
+38 -3
View File
@@ -16,6 +16,7 @@
//
static CoreCallbacks* l_CoreCallbacks = nullptr;
static bool l_showVerboseMessages = false;
//
// Exported Functions
@@ -35,9 +36,12 @@ bool CoreCallbacks::Init(void)
{
// needed for Qt
qRegisterMetaType<CoreDebugMessageType>("CoreDebugMessageType");
qRegisterMetaType<CoreDebugMessageType>("CoreStateCallbackType");
this->LoadSettings();
l_CoreCallbacks = this;
return CoreSetupCallbacks(this->coreDebugCallback);
return CoreSetupCallbacks(this->coreDebugCallback, this->coreStateCallback);
}
void CoreCallbacks::Stop(void)
@@ -45,12 +49,43 @@ 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;
}
// skip non-fatal interpreter errors
if (type == CoreDebugMessageType::Error)
{
if (message == "DIV_S by 0" ||
message == "DIV_D by 0")
{
return;
}
}
emit l_CoreCallbacks->OnCoreDebugCallback(type, QString::fromStdString(context), QString::fromStdString(message));
}
void CoreCallbacks::coreStateCallback(CoreStateCallbackType type, int value)
{
if (l_CoreCallbacks == nullptr)
{
return;
}
emit l_CoreCallbacks->OnCoreStateCallback(type, value);
}
+6 -2
View File
@@ -27,11 +27,15 @@ 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);
static void coreStateCallback(CoreStateCallbackType type, int value);
signals:
void OnCoreDebugCallback(CoreDebugMessageType type, QString message);
void OnCoreDebugCallback(CoreDebugMessageType type, QString context, QString message);
void OnCoreStateCallback(CoreStateCallbackType type, int value);
};
#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
+5 -8
View File
@@ -22,25 +22,22 @@ EmulationThread::~EmulationThread(void)
void EmulationThread::SetRomFile(QString file)
{
this->rom_File = file;
this->rom = file;
}
void EmulationThread::SetDiskFile(QString file)
{
this->disk_File = file;
this->disk = file;
}
void EmulationThread::run(void)
{
emit this->on_Emulation_Started();
bool ret;
ret = CoreStartEmulation(this->rom_File.toStdU32String(), this->disk_File.toStdU32String());
bool ret = CoreStartEmulation(this->rom.toStdU32String(), this->disk.toStdU32String());
if (!ret)
{
this->error_Message = QString::fromStdString(CoreGetError());
this->errorMessage = QString::fromStdString(CoreGetError());
}
emit this->on_Emulation_Finished(ret);
@@ -48,5 +45,5 @@ void EmulationThread::run(void)
QString EmulationThread::GetLastError(void)
{
return this->error_Message;
return this->errorMessage;
}
+5 -6
View File
@@ -32,9 +32,9 @@ class EmulationThread : public QThread
QString GetLastError(void);
private:
QString rom_File;
QString disk_File;
QString error_Message;
QString rom;
QString disk;
QString errorMessage;
signals:
void on_Emulation_Started(void);
@@ -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);
+41 -22
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);
@@ -68,54 +70,71 @@ void RomSearcherThread::rom_Search(QString directory)
filter << "*.NDD";
filter << "*.D64";
filter << "*.ZIP";
filter << "*.7Z";
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;
int count = 0;
QList<QString> roms;
while (romDirIt.hasNext())
{
QString file = romDirIt.next();
roms.push_back(romDirIt.next());
}
int romAmount = std::min(this->maxItems, (int)roms.size());
for (int i = 0; i < romAmount; i++)
{
QString file = roms.at(i);
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()) &&
// open rom, retrieve rom settings, header & type
ret = CoreOpenRom(file.toStdU32String()) &&
CoreGetCurrentRomSettings(settings) &&
CoreGetCurrentRomHeader(header);
CoreGetCurrentRomHeader(header) &&
CoreGetRomType(type);
// 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)
{
return;
}
emit this->on_Rom_Found(file, header, settings);
emit this->RomFound(file, type, header, settings, (i + 1), romAmount);
}
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);
}

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